Asyncio для веб-скрейпинга: правильное выполнение параллельных запросов
TL;DR
asyncio улучшает пропускную способность для многих независимых сетевых ожиданий; он не делает парсинг HTML быстрее и не дает разрешения увеличить частоту запросов к сайту.
Переиспользуйте один aiohttp.ClientSession, установите общие и соединительные тайм-ауты, и ограничьте как глобальное, так и пер-хостово конкурентное выполнение.
Семафор ограничивает одновременные задачи, а не запросы в секунду. Добавьте явную синхронизацию по хостам, когда источник этого требует.
Повторяйте только временные ошибки, такие как 429, 502, 503 и 504, с ограниченной задержкой и обработкой Retry-After; не повторяйте слепо каждый ответ 4xx.
Для сайтов с рендерингом JavaScript или рекурсивным обнаружением вызывайте управляемое рендеринг и Crawl API, а не ожидайте, что aiohttp выполнит JavaScript.
Когда следует использовать Asyncio для веб-скрапинга?
Используйте asyncio, когда скрепер проводит большую часть своего времени, ожидая множество разрешенных HTTP-ответов. Один рабочий процесс может управлять несколькими активными запросами без отдельного потока для каждого запроса. Преимущество зависит от задержки источника, разрешенной частоты запросов, стоимости парсинга и хранилища на уровне ниже. Если источник разрешает только один запрос каждые несколько секунд, асинхронный клиент не может законно превратить это в высокочастотный скан. Продукт Nstdata Crawl является управляемым вариантом для шагов получения и преобразования, обсуждаемых здесь.
Попробуйте Nstproxy Crawl - Начните Бесплатно Уже Сегодня
Документация по задачам Python asyncio объясняет, как планируются корутины. Руководство клиента aiohttp рекомендует переиспользовать сессию, а не создавать новую для каждого запроса. Сессия сохраняет пул соединений и общую конфигурацию. Используйте этот учебник только для источников, которые вы уполномочены собирать.
Руководство по рендерингу в масштабе охватывает другую узкую функцию по сравнению с конкурентным доступом HTTP.
Что вам нужно перед началом?
Установите Python 3 и aiohttp в виртуальной среде. Пример также использует Beautiful Soup для извлечения заголовка из возвращенного HTML:
Создайте короткий список разрешенных URL, обратите внимание на разрешенную частоту запросов для каждого хоста и выберите контактное User-Agent. Для Nstdata Crawl получите учетную запись и API-ключ; задокументированный заголовок аутентификации — x-api-key. Вам не нужны значения Proxy Host, Port, Username, Password или Protocol для стандартного управляемого запроса Crawl, так как Nstdata обрабатывает маршрутизацию прокси.
Как конкуренция отличается от ограничения скорости?
Конкуренция — это количество запросов в ожидании одновременно. Частота — это то, как часто начинаются новые запросы. Семафор из трех может создать три запроса в один и тот же момент, а затем еще три, как только ответы завершатся. Это может нарушить желаемую синхронизацию источника, даже если активно лишь три запроса. Используйте интервал начала для каждого хоста или токенный бакет, когда хост требует максимальной частоты.
Установите ограничения на трех уровнях: общее количество активных задач, limit_per_host пула соединений и интервал начала для каждого хоста. Сохраняйте их консервативными в ходе пилотного проекта и корректируйте в зависимости от политики источника, ответов 429, задержки и уровня ошибок. Пример ниже использует одну секунду между запусками для каждого хоста и максимум три соединения на хост; эти настройки иллюстративные, а не универсально безопасная скорость.
Лучше всего для: Несколько статических страниц, данные которых появляются в первоначальном HTTP-ответе.
Шаг 1. Сохраните сценарий ниже как async_scrape.py. Замените URLS на разрешенные URL и настройте MIN_HOST_INTERVAL в соответствии с фактической политикой источника.
Шаг 2. Запустите python async_scrape.py и проверьте каждый результат или исключение. Успешный ответ example.com должен содержать заголовок документа; скрипт не утверждает, что каждая целевая страница имеет элемент <title>.
Шаг 3. Добавьте сохранение только после проверки извлеченных полей. Храните URL, время получения, версию парсера и причину отказа. Замените print на идемпотентную запись, ключевую по каноническому URL или идентификатору источника.
Ограничение: Вспомогательная функция Retry-After обрабатывает числовые секунды. Значение HTTP-даты требует парсера даты перед использованием в производстве. Пример также удерживает блокировку темпа по хосту во время ожидания, намеренно сериализуя начало запросов для этого хоста.
Спецификация HTTP Semantics определяет статус и поведение заголовков, связанных с повторными попытками, которые клиент должен интерпретировать.
Как обрабатывать тысячи URL без создания тысяч задач одновременно?
Метод 2: Используйте ограниченную рабочую очередь
Лучше всего: Для больших списков URL или непрерывно обнаруживаемых страниц.
Шаг 1. Поместите утвержденные URL в надежную очередь или базу данных с уникальным ключом, счетчиком попыток и временем следующей допустимой выборки. Очередь asyncio.Queue в памяти полезна в рамках процесса, но не может восстановиться после сбоя машины.
Шаг 2. Запустите фиксированное количество работников, которые каждый вытаскивают один URL, вызывают ограниченный извлекатель, проверяют запись и подтверждают задачу только после записи надежного вывода.
Шаг 3. Запишите неудачи с указанием причины и времени повторной попытки. Мертвые письма для URL, исчерпавших попытки или нарушивших политику. Применяйте обратное давление, когда парсер или уровень хранения отстают.
Ограничение:asyncio.gather по более чем миллиону корутин URL потребляет память даже с семафором. Очередь ограничивает создание задач и предоставляет место для контрольной точки работы.
Шаг 1. Получите ключ API Nstdata и определите утвержденную область URL. Crawl API документирует аутентификацию x-api-key и задачи сайта с maxDepth, maxPages, includeUrls и excludeUrls.
Шаг 2. Отправьте ограниченную задачу на Nstdata Crawl. Проверяйте статус и извлекайте завершенные страницы через задокументированные конечные точки. Nstdata обрабатывает обнаружение страниц, рекурсивный обход, рендеринг JavaScript и маршрутизацию прокси.
Шаг 3. Разобрать возвращенный Markdown, HTML, сырые данные, ссылки, скриншоты или PDF в соответствии с потребностями вашего приложения. Проверьте содержимое и сохраните происхождение перед индексацией или обучением.
Ограничение: Управляемый API не заменяет ваши разрешения на источник, расписание между сайтами или произвольное извлечение схемы продукта. Не используйте его для обхода ограничений доступа.
Почему не удается выполнить параллельные запросы или они возвращают некорректные данные?
429 означает, что источник ограничивает количество запросов; уменьшите количество запусков на хост и учитывайте рекомендации по повторным попыткам в ответе. Тайм-аут может указывать на проблемы с сетью или медленный источник; повторите попытку небольшое количество раз и зафиксируйте неудачу, вместо того чтобы повторять бесконечно. 200 с пустым заголовком может быть JavaScript-оболочкой, страницей согласия или несовпадением парсера. Проверьте возвращенный HTML и сетевое поведение браузера перед изменением параллелизма.
Отслеживайте количество принятых записей в секунду, медиану и задержки в хвосте, 429 скорость, количество повторных попыток и возраст очереди по хосту. Высокое количество запросов с низкой доходностью принятых записей — это проблема качества. Если один домен начинает сбой, приостановите этот домен, пока другие утвержденные источники продолжают работать.
Как сделать пример безопасным для производства?
Переместите ввод URL в надежную очередь и храните один конечный результат на URL. Большой вызов gather создает coroutine для каждого ввода до запуска семафора, поэтому это не подходит для очень большого манифеста. Фиксированный пул рабочих, читающих из очереди, поддерживает ограничение памяти и позволяет истекать лицензии потерянного работника. Подтверждение должно следовать за надежным хранением принятой записи или результата неудачи.
Добавьте запись политики, специфичную для источника. Интервал в одну секунду и три соединения на хост в примере являются иллюстративными. Реальные настройки должны основываться на разрешенной схеме доступа сайта и пилоте. Разные хосты могут требовать разных начальных интервалов. Глобальный семафор защищает ваш процесс, но не предотвращает несколько распределенных рабочих от совместного превышения бюджета хоста. Для распределенных обходов поместите состояние скорости в общую программу планирования или назначьте каждому хосту одну скоординированную группу рабочих.
Улучшите обработку повторных попыток перед большими запусками. Числовые значения Retry-After поддерживаются в примере; значения HTTP-дат нуждаются в парсинге. Добавьте избегание «сбоя» для предотвращения повторных попыток нескольких работников в один и тот же момент. Установите максимальное время ожидания и попытки, затем мертвая запись заданий, которые не могут быть успешными. Не повторять 401, 403 или неверные URL, как будто дополнительные попытки дадут доступ.
Наконец, держите парсинг HTML вне цикла событий, если он становится ресурсозатратным. Небольшие операции Beautiful Soup могут быть приемлемы, но парсинг очень больших страниц или выполнение сложной извлечения в одном цикле может задерживать все запросы. Измерьте задержку цикла событий и перенесите тяжелый парсинг в рабочий процесс или на отдельный этап, когда это необходимо. Асинхронный сетевой I/O и параллельная работа CPU решают разные узкие места.
Что следует отслеживать в параллельном скрепере?
Записывайте задержки и результаты по хосту. Глобальное среднее скрывает тот факт, что один источник истекает или возвращает страницы с мягкой ошибкой. Отслеживайте активные запросы, старт запроса по хосту, скорость 429, тайм-ауты, байты ответа, доходность принятых записей, попытки повторных попыток и возраст очереди. Подайте сигнал о постоянном ухудшении качества, а не просто о сбоях процессов.
Используйте образец принятия после изменения параллелизма. Более высокая пропускная способность может увеличить количество неполных ответов, страницы с вызовом или нагрузку на источник. Сравните принятые записи в секунду и единичную стоимость, и убедитесь, что правила со стороны источника все еще соблюдаются. Если доходность принятия падает при увеличении количества запросов, уменьшите скорость и проверьте образец перед дальнейшей масштабированием.
Храните сырые и принятые записи отдельно на панели управления. Всплеск 200 ответов не является успехом, если большинство страниц содержат шаблон ошибки. Проверьте ожидаемый маркер страницы, заголовок, тип содержимого и обязательные поля, прежде чем считать запись принятой. Это дает операционной команде сигнал приостановить один источник, пока остальная очередь продолжается.
Нет. Семафор ограничивает одновременную работу. Используйте механизм установки темпа для каждого хоста, чтобы контролировать запуск запросов со временем.
В: Может ли aiohttp скрапировать страницу, отрендеренную JavaScript?aiohttp получает HTTP-ответы, но не выполняет JavaScript на странице. Используйте рендеринг браузера или управляемый путь обхода для контента, сгенерированного после загрузки.
В: Должен ли я использовать asyncio.gather для одного миллиона URL?
Нет. Передавайте ограниченное количество работников из надежной очереди, чтобы использование памяти и восстановление задания оставались под контролем.
Этот учебник по Python переходит от одной статической страницы к проверенным записям и управляемому рендерингу. Он включает в себя запускаемые примеры, диагностику сбоев, управление версиями и готовый к искусственному интеллекту договор на данные.
Marcus Chen
Oct. 29th 2026
Сканируйте целые сайты одним API-запросом
Успешность 99,8% с рендерингом JavaScript
Получайте чистые данные для LLM в разных форматах
Преобразуйте любой сайт в Markdown, HTML, JSON, ссылки, PDF и другие форматы без управления инфраструктурой сканирования.