Как в Python реализовать асинхронный парсинг сайта с использованием библиотеки aiohttp?
Асинхронный парсинг сайтов с использованием библиотеки aiohttp позволяет значительно ускорить сбор данных по сравнению с синхронными подходами. Вместо последовательного ожидания ответа от каждого сервера, asyncio и aiohttp позволяют отправлять множество запросов одновременно.
**Установка зависимостей**
Перед началом работы установите необходимые библиотеки:
pip install aiohttp asyncio beautifulsoup4
**Базовый пример асинхронного парсинга**
python
import asyncio
import aiohttp
from bs4 import BeautifulSoup
async def fetch_page(session, url):
async with session.get(url) as response:
return await response.text()
async def parse_page(session, url):
html = await fetch_page(session, url)
soup = BeautifulSoup(html, ‘html.parser’)
title = soup.find(‘h1’)
return {‘url’: url, ‘title’: title.text if title else ‘N/A’}
async def main(urls):
async with aiohttp.ClientSession() as session:
tasks = [parse_page(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
urls = [
‘https://example.com/page1’,
‘https://example.com/page2’,
‘https://example.com/page3′,
]
results = asyncio.run(main(urls))
for r in results:
print(r)
**Ключевые принципы**
1. **ClientSession** — создавайте одну сессию на всё время работы парсера. Это экономит ресурсы за счёт переиспользования TCP-соединений.
2. **asyncio.gather** — позволяет запускать несколько корутин параллельно и собирать результаты.
3. **Ограничение concurrency** — чтобы не перегружать сервер, используйте `asyncio.Semaphore`:
python
semaphore = asyncio.Semaphore(10) # не более 10 одновременных запросов
async def fetch_with_limit(session, url, semaphore):
async with semaphore:
async with session.get(url) as response:
return await response.text()
**Обработка ошибок**
Всегда обрабатывайте исключения, так как сетевые запросы могут завершаться неудачей:
python
async def safe_fetch(session, url):
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response:
response.raise_for_status()
return await response.text()
except aiohttp.ClientError as e:
print(f’Ошибка при запросе {url}: {e}’)
return None
**Советы по производительности**
— Устанавливайте таймауты через `aiohttp.ClientTimeout`, чтобы избежать зависания.
— Добавляйте заголовки `User-Agent` для имитации браузера.
— Используйте `asyncio.Semaphore` для контроля нагрузки.
— Сохраняйте результаты в CSV с помощью стандартного модуля `csv` или `pandas`.
Асинхронный подход с aiohttp может ускорить парсинг в десятки раз по сравнению с синхронными библиотеками типа `requests`, особенно при работе с большим количеством URL.
