【发布时间】:2016-05-30 16:41:01
【问题描述】:
我想为具有动态等待的爬虫创建自定义请求管理器。
我的爬虫需要向禁止来自同一 IP 地址的并行请求的站点发出请求。如果发生此类阻塞,请求将返回 HTTP 错误代码 403、503、429 等。
如果出现错误,我想等待一段时间并重复请求。但为了简单起见,他们只需调用 get 并接收正确的页面。
我想使用 aiohttp 和 Python 3.5 的新 async with 语法,因此我的解析器类可以使用 async with如果他们像这样使用 aiohttp.ClientSession,我的 requester 类也一样:
# 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
如果 requester 是 aiohttp.ClientSession,那么 response 是 aiohtpp.ClientResponse 有 __aenter__ 和 __aexit__ 方法,因此 async with 可以按预期工作。
但是如果我把我的 requester 类放在中间,它就不再工作了。
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 是协程函数,所以我会等待它。结果是具有 __aenter__ 或 __aexit__ 的 aiohttp.ClientResponse。但是如果返回 parser 的 async with 代码块返回奇怪的错误。
你能说我需要用 aiohttp.ClientSession 类替换我的 requester 类吗?
【问题讨论】:
-
你能用minimal reproducible example扩展“它不再工作”吗?
标签: python-3.5 python-asyncio aiohttp