Потери данных при асинхронном парсинге с использованием библиотеки Asyncio+aiohttp
Я только начал вникать в асинхронку и еще плохо ориентируюсь в этом. Практикуюсь в написание парсера, возникла следующая проблема: При парсинге я сохраняю словари - {имя:цена} в общий список, на каждой странице 16 книг, я паршу 80 страниц, в результате длинна списка по окончании программы должна быть 1280. Проблема в том что парсер работает через раз, бывает одает пустой список, либо длинна меньше в 2-3 раза, тоесть есть потери данных, код прилагаю
from bs4 import BeautifulSoup as BS
import aiohttp
import asyncio
import time
from fake_useragent import UserAgent
URL = 'https://bashenka.by/60-katalog-brendy?p={}'
data = []
headers = {
'user-agent': UserAgent().chrome
}
async def get_info_book(session, page):
url = URL.format(page)
async with session.get(url=url) as responce:
html = await responce.text()
soup = BS(html, 'html.parser')
books = soup.find_all(class_='right-block')
for book in books:
name = book.find('h5').text.strip()
price = soup.find(class_='price product-price').text
data_dict = {name:price}
data.append(data_dict)
print('Страница ', page)
async def main():
async with aiohttp.ClientSession(headers=headers) as session:
task_list = [asyncio.create_task(get_info_book(session, i)) for i in range(1, 80)]
await asyncio.gather(*task_list)
print(data)
print(len(data))
start = time.time()
await main()
print(time.time()-start)
Ответы (1 шт):
добавил параметр lock в функцию get_info_book, который является объектом asyncio.Lock. При каждой итерации цикла for мы захватываем блокировку и добавляем словарь data_dict в список data, чтобы избежать состояния гонки.
from bs4 import BeautifulSoup as BS
import aiohttp
import asyncio
import time
from fake_useragent import UserAgent
URL = 'https://bashenka.by/60-katalog-brendy?p={}'
data = []
headers = {
'user-agent': UserAgent().chrome
}
async def get_info_book(session, page, lock):
url = URL.format(page)
async with session.get(url=url) as responce:
html = await responce.text()
soup = BS(html, 'html.parser')
books = soup.find_all(class_='right-block')
for book in books:
name = book.find('h5').text.strip()
price = soup.find(class_='price product-price').text
data_dict = {name:price}
async with lock:
data.append(data_dict)
print('Страница ', page)
async def main():
lock = asyncio.Lock()
async with aiohttp.ClientSession(headers=headers) as session:
tasks = []
for page in range(1, 81):
task = asyncio.create_task(get_info_book(session, page, lock))
tasks.append(task)
await asyncio.gather(*tasks)
if __name__ == '__main__':
start_time = time.monotonic()
asyncio.run(main())
end_time = time.monotonic()
print('Elapsed time:', end_time - start_time)
print('Data length:', len(data))