3

動的に待機するクローラー用のカスタム リクエスト マネージャーを作成したいと考えています。
私のクローラーは、同じ IP アドレスからの並列リクエストを禁止するサイトにリクエストを送信する必要があります。このようなブロックが発生した場合、リクエストは HTTP エラー コード 403、503、429 などで返されます。エラーが発生した
場合は、しばらく待ってからリクエストを繰り返します。しかし、パーサーを単純にするために、get を呼び出して正しいページを受け取るだけです。Python 3.5の構文でaiohttpと新しいasync
を使用したいので、パーサー クラスはaiohttp.ClientSessionを次のように使用した場合と同じように、リクエスター クラスに対してasyncを使用できます。

# 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の場合、レスポンス__aenter__および__aexit__メソッドを持つaiohtpp.ClientResponseであるため、非同期は期待どおりに動作します。 しかし、リクエスタークラスを真ん中に置くと、もう機能しません。

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です。しかし、ブロックを返すパーサー非同期コードを返すと、奇妙なエラーが返されます。

aiohttp.ClientSessionのように、リクエスタークラスで何を置き換える必要があるか教えていただけますか?

4

1 に答える 1

1

async withプロトコルをサポートするには、追加のコードを記述する必要があります。

インスピレーションについては、 client.request()_RequestContextManagerを参照してください。

于 2016-06-01T13:27:47.220 に答える