Почему произошла ошибка asyncio.исключения.Тайм-аут или

#python #python-asyncio #aiohttp

Вопрос:

В качестве данных я передаю список категорий, а затем собираю информацию на странице. Код отлично работает, если обработать около 5000 записей. Превышение этого предела приводит к ошибке тайм-аута через некоторое время.

Я попробовал ClientTimeout в ClientSession, но результат остался прежним. Скажи мне, в чем проблема.

Код:

 from aiohttp import ClientTimeout
timeout = ClientTimeout(total=600)
START = time.monotonic()
start_time = time.time()
code_VEND_list = []

class RateLimiter:
    """Rate limits an HTTP client that would make get() and post() calls.
    Calls are rate-limited by host.
    https://quentin.pradet.me/blog/how-do-you-rate-limit-calls-with-aiohttp.html
    This class is not thread-safe."""
    RATE = 2  # one request per second
    MAX_TOKENS = 5

    def __init__(self, client):
        self.client = client
        self.tokens = self.MAX_TOKENS
        self.updated_at = time.monotonic()

    async def get(self, *args, **kwargs):
        await self.wait_for_token()
        now = time.monotonic() - START
        print(f'{now:.0f}s: ask {args[0]}')
        return self.client.get(*args, **kwargs)

    async def wait_for_token(self):
        while self.tokens < 1:
            self.add_new_tokens()
            await asyncio.sleep(0.1)
        self.tokens -= 1

    def add_new_tokens(self):
        now = time.monotonic()
        time_since_update = now - self.updated_at
        new_tokens = time_since_update * self.RATE
        if self.tokens   new_tokens >= 1:
            self.tokens = min(self.tokens   new_tokens, self.MAX_TOKENS)
            self.updated_at = now

async def fetch_one(client, i):
    url = f'https://example.com/product/{i}'
    async with await client.get(url) as resp:
        resp_text = await resp.text()
        bs0bj = BeautifulSoup(resp_text, 'lxml')
        code_EAN = re.sub('^s |n|r|s 

Код ошибки:

 Traceback (most recent call last):
  File "F:PythontestStack.py", line 89, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "C:UsersAppDataLocalProgramsPythonPython39libasynciobase_events.py", line 642, in run_until_complete
    return future.result()
  File "F:PythontestStack.py", line 81, in main
    await asyncio.gather(*tasks)
  File "F:PythontestStack.py", line 52, in fetch_one
    async with await client.get(url) as resp:
  File "F:Pythonvenvlibsite-packagesaiohttpclient.py", line 1117, in __aenter__
    self._resp = await self._coro
  File "F:Pythonvenvlibsite-packagesaiohttpclient.py", line 544, in _request
    await resp.start(conn)
  File "F:Pythonvenvlibsite-packagesaiohttpclient_reqrep.py", line 905, in start
    self._continue = None
  File "F:Pythonvenvlibsite-packagesaiohttphelpers.py", line 656, in __exit__
    raise asyncio.TimeoutError from None
asyncio.exceptions.TimeoutError
 

Комментарии:

1. Вы устанавливаете тайм-аут в 600 секунд во второй строке, который затем используете в сеансе клиента. Это приведет к появлению тайм-аута, когда пройдет 600 секунд, а клиент не закончил.

2. Я попробовал без параметра total = 600, ошибка повторяется.

3. Найдено в документации: "По умолчанию aiohttp использует общий тайм-аут 300 секунд (5 минут), это означает, что вся операция должна завершиться за 5 минут. Все поля являются плавающими, Нет или 0 отключает определенную проверку времени ожидания, см. Ссылку ClientTimeout для значений по умолчанию и дополнительных сведений." Я установил total=0, тест в течение часа, все работает нормально. Я дам тебе знать, если что-то изменится.

, '',
bs0bj.find('div', {'class': 'item_'}).get_text())
code_VEND_list.append(code_EAN)

def file_writher():
income1 = pd.DataFrame({'Code': code_VEND_list})
income_sheets = {'MySite-Base': income1}
writer = pd.ExcelWriter('./Test.xlsx', engine='xlsxwriter')
for sheet_name in income_sheets.keys():
income_sheets[sheet_name].to_excel(writer, sheet_name=sheet_name, index=False)
writer.save()

async def main():
vendor_seorce = []
workbook = xlrd.open_workbook('Source.xlsx')
worksheet = workbook.sheet_by_index(0)
for vend_code in worksheet.col_values(0):
vendor_seorce.append(vend_code)

async with aiohttp.ClientSession(timeout=timeout) as client:
client = RateLimiter(client)
tasks = [asyncio.ensure_future(fetch_one(client, id_cat)) for id_cat in vendor_seorce]
await asyncio.gather(*tasks)

finish_time = time.time() - start_time
print('Done!')
print(f'Time: {finish_time}')
file_writher()

if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
Код ошибки:


Комментарии:

1. Вы устанавливаете тайм-аут в 600 секунд во второй строке, который затем используете в сеансе клиента. Это приведет к появлению тайм-аута, когда пройдет 600 секунд, а клиент не закончил.

2. Я попробовал без параметра total = 600, ошибка повторяется.

3. Найдено в документации: «По умолчанию aiohttp использует общий тайм-аут 300 секунд (5 минут), это означает, что вся операция должна завершиться за 5 минут. Все поля являются плавающими, Нет или 0 отключает определенную проверку времени ожидания, см. Ссылку ClientTimeout для значений по умолчанию и дополнительных сведений.» Я установил total=0, тест в течение часа, все работает нормально. Я дам тебе знать, если что-то изменится.