【问题标题】:How to reset/clear aiohttp session如何重置/清除 aiohttp 会话
【发布时间】:2018-03-12 01:59:43
【问题描述】:

我一直在使用aiohttp 和反向连接代理进行一些测试(每个请求的 IP 都会更改)。使用反向连接代理的最大问题是有时您没有得到一个好的代理。无论如何,无论如何,我仍然需要通过该特定 URL 的请求。我创建了一个请求http://ip4.me 10,000 次并检索 IP 地址的示例。一开始一切正常,但最终,它开始出现错误:

赋值前引用的局部变量“ip”

这个错误的原因是因为我请求后得到的页面是一些重定向页面,它将你带到一些随机站点。这是 HTML(真的没关系,但我想我会画出完整的画面)。

<html><head><meta content="2;url=http://ip4.me/?" http-equiv="refresh"/></head><body><iframe frameborder="0" id="f" style="width:1;height:1"></iframe><script>document.getElementById("f").src="http://168.126.130.229/tm/?a=CR&b=WIN&c=300017519516&d=32&e=2205&f=aXA0Lm1l&g=1520816781875&h="+Date.now()+"&y=0&z=0&x=1&w=2017-11-29&in=2205_00002350&id=20180312"</script></body></html>

我猜我得到这个页面是因为它是对如此多的请求或类似的东西的某种防御?现在,通常当我收到请求错误(代理错误、加载时间过长等)时,我会继续尝试,直到获得良好响应(本示例运行时 90% 的时间都有效)。就像我之前提到的,在最后(可能还有 10 个请求要做)。它将继续获取我在上面发布的 HTML 以及我在上面发布的错误。这将不断发生。

我认为发生这种情况的唯一原因是正在使用相同的会话,因此网站以某种方式知道这一点,只是不断给我这个重定向页面(永远不允许它跳出 While 循环)。当然,可能还有其他原因。如果有人对为什么会发生这种情况有任何见解?或者甚至是重试请求的更好方法(如果我得到一个错误的代理等),我们将不胜感激!以下是我的完整工作示例,如果您有任何问题,请告诉我。感谢您的宝贵时间!

import asyncio
import aiohttp

from bs4 import BeautifulSoup
from datetime import datetime
from aiohttp.resolver import AsyncResolver

class Proxy:
    def __init__(self, headers, proxy):
        self.headers = headers
        self.proxy = proxy

    async def build(self, dataset):
        tasks = []
        resolver = AsyncResolver(nameservers=["8.8.8.8", "8.8.4.4"])
        connector = aiohttp.TCPConnector(limit=1500, limit_per_host=0, resolver=resolver, use_dns_cache=False)
        async with aiohttp.ClientSession(connector=connector) as session:
            for data in range(0,dataset):
                task = asyncio.ensure_future(self.fetch(session, data))
                tasks.append(task)
            r = await asyncio.gather(*tasks)
            return r

    async def fetch(self, session, data):
        while True:
            try:
                async with session.get('http://ip4.me', headers=self.headers, proxy=self.proxy, timeout=60, ssl=False, allow_redirects=False) as resp:
                    assert resp.status == 200
                    r = await resp.read()
                    soup = BeautifulSoup(r, 'lxml')
                    for font in soup.find_all('font'):
                        ip = font.text
                    print (data, ip)
                    return ip
            except Exception as e:
                print (e)

if __name__ == '__main__':
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'}
    proxy = 'XXX.XX.X.XXX:XXXXX'
    proxy = "http://{}".format(proxy)
    dataset = 10000

    px = Proxy(headers, proxy)

    startTime = datetime.now()
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    future = asyncio.ensure_future(px.build(dataset))
    ip = loop.run_until_complete(future)
    loop.close()
    print (datetime.now() - startTime)

【问题讨论】:

  • 您在 for 循环的主体中分配 ip。如果没有字体标签,它将永远不会收到值。

标签: python python-3.x python-3.6 python-asyncio aiohttp


【解决方案1】:

爬行是一个很大的话题。

在您的表达中,我认为您在每个请求中使用不同的代理。但是在您的代码中,我认为您对每个请求都使用相同的代理和相同的标头。

因此,在这种情况下,无论您如何在 python 代码中更改会话,服务器都很容易识别您。因为你的IP从未改变。够了。当服务器认为你应该被禁止时,它会禁止你的IP,然后无论你怎么尝试,你都会被完全屏蔽。

一些网站提供专业的服务来解决爬虫禁止问题。他们在一段时间内为每个不同的请求使用不同的代理。他们使用随机生成的用户代理来装扮成不同的浏览器。他们还使用庞大的数据库来决定相关的策略。

所以这并不容易。如果您尝试获取少量数据,则可以放慢速度。

使用新会话

....
resolver = AsyncResolver(nameservers=["8.8.8.8", "8.8.4.4"])
connector = aiohttp.TCPConnector(limit=1500, limit_per_host=0, resolver=resolver, use_dns_cache=False, force_close=True)
sessions = []
for data in range(0,dataset):
    session = aiohttp.ClientSession(connector=connector)
    task = asyncio.ensure_future(self.fetch(session, data))
    tasks.append(task)
    sessions.append(session)
r = await asyncio.gather(*tasks)
[session.close() for session in sessions]
return r
....

force_close=True 可能没用,因为您为每个请求使用不同的会话。

【讨论】:

  • 什么?我清楚地说我正在使用反向连接代理和“每个请求的 IP 更改”?所以不,我没有为每个请求使用相同的 IP。我正在使用反向连接代理,它为每个请求提供一个新 IP,并且一次最多可以发出 1500 个请求。在回答之前,请一直阅读我的问题。谢谢。
  • 我只是没有意识到你代码中的proxy实际上是一个IP池。所以让你有这样的情绪?为什么您在我的答案底部的第二段中看不到另一个可能的原因?用户代理识别浏览器,因此如果您使用相同的用户代理发送请求,服务器仍然可以识别您。这个网站上的每个人都在努力帮助别人。你不需要这么情绪化。
  • 情绪化?我只是说要阅读我的问题......但无论如何,用户代理不会产生这样的影响。有多少台计算机使用相同的用户代理?无论如何,我已经尝试过轮换用户代理,但它什么也没做。无论如何...您对如何重置/清除会话有任何见解吗?我认为这是主要问题。
  • 您只需要为每个请求创建新会话。答案已编辑。
  • 实际上,force_close=True 是它起作用的原因。我不需要做任何其他事情,只需要添加它。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
  • 2015-03-01
  • 2013-12-06
  • 2012-04-22
  • 1970-01-01
  • 2010-09-30
  • 2019-01-19
相关资源
最近更新 更多