3

我想为具有动态等待的爬虫创建自定义请求管理器。
我的爬虫需要向禁止来自同一 IP 地址的并行请求的站点发出请求。如果发生这种阻塞,请求返回 HTTP 错误代码 403、503、429 等
。如果出现错误,我想等待一段时间并重复请求。但是为了简单起见,他们只调用 get 并接收正确的页面。
我想将aiohttp和新的async 与Python 3.5的语法一起使用,因此如果他们像这样使用aiohttp.ClientSession,我的解析器类可以以同样的方式对我的请求者类使用async with

# somewhere in a parser
async def get_page(self, requester, page_index):
  async with requester.get(URL_FMT.format(page_index)) as response:
    html_content = await response.read()
    result = self.parsing_page(html_content)
    return result

如果请求者aiohttp.ClientSession,则响应aiohtpp.ClientResponse,它具有__aenter____aexit__方法,因此可以按预期异步工作。
但是如果我把我的请求者类放在中间,它就不再工作了。

Traceback (most recent call last):
  File "/opt/project/api/tornado_runner.py", line 6, in <module>
    from api import app
  File "/opt/project/api/api.py", line 20, in <module>
    loop.run_until_complete(session.login())
  File "/usr/local/lib/python3.5/asyncio/base_events.py", line 337, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/usr/local/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "/opt/project/api/viudata/session.py", line 72, in login
    async with self.get('https://www.viudata.com') as resp:
AttributeError: __aexit__
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7f44f61ef240>

它看起来像这样。

class Requester:
   def __init__(self, session: aiohttp.ClientSession):
     self.session = session

   async def get(self, *args, **kwargs):
     is_result_successful = False
     while not is_result_successful:
       response = await self.session.get(*args, **kwargs)
       if response.status in [503, 403, 429]:
          await self.wait_some_time()
       else:
          is_result_successful = True
     return response

据我了解self.session.get是协程函数,所以我会等待它。结果是aiohttp.ClientResponse具有__aenter____aexit__。但是如果返回它parserasync with block 代码返回奇怪的错误。

你能说一下我需要用我的请求者类替换什么,就像用aiohttp.ClientSession 一样吗?

4

1 回答 1

1

您应该编写额外的代码来支持async with协议。

请参阅client.request()_RequestContextManager以获得灵感。

于 2016-06-01T13:27:47.220 回答