Ошибка в создании тасков asyncio python3.10
Изучаю асинхронность в питоне. Очень сложная для меня тема. Есть такой код, который парсит магазин кроссовок и складывает данные в .json файл. В синхронном стиле все работает, но оооочень долго. Решил переписать, используя асинхронность, но банально не понимаю почему выдает исключение RuntimeError: Task got bad yield:*адрес корутины в памяти*.
import aiohttp
import json
from time import time
URL = 'https://xn--80awro.xn--p1ai/krossovki?start={position}&tmpl=component'
HEADERS = {
'Accept': '*/*',
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0'
}
SHOP_URL = 'https://хасл.рф/'
all_trainers_data = {'trainers': []}
async def get_content(url: str, session: aiohttp.ClientSession) -> None:
"""Отвечает за отправку GET-запроса на страницу с данными"""
print(f'Going to url {url}...')
async with session.get(url=url, headers=HEADERS) as response:
json_data = await response.json()
await parse_json(json_data['rows'])
async def parse_json(data: dict) -> None:
"""Отвечает за парсинг данных формата json, складывает все в общий словарь с данными"""
for iterator in range(0, 40):
current_trainers_json = data[iterator]
attrs = current_trainers_json['attributes'][0]['list']
able_sizes = []
for attr in attrs:
able_sizes.append(attr['name'])
trainers_info = {
'name': current_trainers_json['name'],
'actual_price': current_trainers_json['product_price'],
'old_price': current_trainers_json['product_old_price'],
'discount': current_trainers_json['product_old_price'] - current_trainers_json['product_price'],
'image_url': current_trainers_json['image'],
'link': SHOP_URL + current_trainers_json['product_link'],
'able_size': able_sizes
}
all_trainers_data['trainers'].append(trainers_info)
def write_file(raw_trainers_data: dict) -> None:
"""Преобразует данные в объект json, а так же записывает их в .json файл"""
with open('хасл_рф_кроссовки.json', 'w') as file:
json.dump(raw_trainers_data, file, indent=4, ensure_ascii=False)
async def main() -> None:
"""Формирует таски"""
async with aiohttp.ClientSession() as session:
tasks = [asyncio.create_task(get_content(URL.format(position=i), session) for i in range(0, 4080, 40))]
await asyncio.gather(*tasks)
write_file(all_trainers_data)
if __name__ == '__main__':
t0 = time()
asyncio.run(main())
print(f'{time() - t0} seconds has passed')
Ответы (2 шт):
Автор решения: Сергей Ш
→ Ссылка
import asyncio
import json
from time import time
import aiohttp
URL = 'https://xn--80awro.xn--p1ai/krossovki?start={position}&tmpl=component'
HEADERS = {
'Accept': '*/*',
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0'
}
SHOP_URL = 'https://хасл.рф/'
async def get_content(url: str, session: aiohttp.ClientSession) -> None:
"""Отвечает за отправку GET-запроса на страницу с данными"""
async with session.get(url=url, headers=HEADERS) as response:
try:
json_data = json.loads(await response.text())
except Exception as ex:
print(ex)
print(response)
return
print(f'Going to url {url}...')
"""Отвечает за парсинг данных формата json, складывает все в общий словарь с данными"""
for trainers_json in json_data['rows']:
trainers_info = {
'name': trainers_json['name'],
'actual_price': trainers_json['product_price'],
'old_price': trainers_json['product_old_price'],
'discount': trainers_json['product_old_price'] - trainers_json['product_price'],
'image_url': trainers_json['image'],
'link': SHOP_URL + trainers_json['product_link'],
'able_size': [attr['name'] for attr in trainers_json['attributes'][0]['list']]
}
return trainers_info
def write_file(raw_trainers_data: dict) -> None:
"""Преобразует данные в объект json, а так же записывает их в .json файл"""
with open('хасл_рф_кроссовки.json', 'w') as file:
json.dump(raw_trainers_data, file, indent=4, ensure_ascii=False)
async def main() -> None:
"""Формирует таски"""
async with aiohttp.ClientSession() as session:
tasks = [asyncio.create_task(get_content(URL.format(position=i), session)) for i in range(0, 4080, 40)]
all_trainers_data = await asyncio.gather(*tasks)
write_file(all_trainers_data)
if __name__ == '__main__':
t0 = time()
asyncio.get_event_loop().run_until_complete(main())
print(f'{time() - t0} seconds has passed')
Автор решения: eri
→ Ссылка
Ошибку из комментария обойти можно так:
data = await resp.json(content_type=None)
На сервере не очень озадачились правильными заголовками:
HTTP/1.1 200 OK
Server: nginx/1.23.0
Date: Sat, 20 Aug 2022 09:09:14 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Content-Type-Options: nosniff