Share This
Связаться со мной
Крути в низ
Categories
//Веб-скрапинг: что можно и чего нельзя делать

Веб-скрапинг: что можно и чего нельзя делать

27.12.2021Category : Python

Веб-скрапинг может показаться легким занятием, и это так. Прежде чем вы это осознаете, вы оказываетесь заблокированным на сайте, а ваш код — на 110% является спагетти-кодом, непригодным для масштабирования.

С вами такое случалось? С нами — тоже, и это не стыдно (ну, разве что чуть-чуть). Сегодня мы обсудим, что можно и чего нельзя делать при веб-скрапинге.

Необходимо чередовать IP-адреса

Самый простой и распространенный метод защиты от скрапинга – бан по IP. Сервер покажет вам первые страницы, но обнаружит слишком много трафика с одного IP-адреса и через некоторое время заблокирует его. Тогда ваша программа придет в негодность. Причем вы не сможете получить доступ к этой веб-странице даже из настоящего браузера. Первый урок веб-скрапинга – никогда не использовать свой реальный IP-адрес.

Каждый запрос оставляет след, даже если вы пытаетесь избежать этого в своем коде. Есть некоторые части сети, которые вы не можете контролировать. Но вы можете использовать прокси для изменения своего IP. Сервер увидит IP, но он не будет вашим. На следующем шаге измените IP-адрес или воспользуйтесь сервисом, который сделает это за вас.

Что это вообще значит?

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

import requests import random  urls = ["http://ident.me"] # ... more URLs proxy_list = [     "54.37.160.88:1080",     "18.222.22.12:3128",     # ... more proxy IPs ]  for url in urls:     proxy = random.choice(proxy_list)     proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}     response = requests.get(url, proxies=proxies)     print(response.text)     # prints 54.37.160.88 (or any other proxy IP)

Обратите внимание, что эти бесплатные прокси могут не работать для вас. Они недолговечны.

veb skraping chto mozhno i chego nelzja delat 3fd92eb - Веб-скрапинг: что можно и чего нельзя делать

Марк Лутц «Изучаем Python»

Скачивайте книгу у нас в телеграм

Скачать ×

Используйте настраиваемый User-Agent

Второй по распространенности механизм защиты от скрапинга – User-Agent. UA – это заголовок, который браузеры отправляют в запросах для идентификации. Обычно он представляет собой длинную строку, в которой объявляется имя браузера, версия, платформа и многое другое. К примеру, для iPhone 13 это будет выглядеть так:

"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"

Нет ничего плохого в отправке User-Agent, и на самом деле это рекомендуется. Проблема в том, какой отправить. Многие HTTP-клиенты отправляют свои собственные, что может показаться подозрительным. Представьте, что ваш сервер получает сотни запросов с UA curl/7.74.0. Наверняка это показалось бы вам подозрительным.

Решение обычно заключается в поиске и использовании валидных UA, как в нашем примере с iPhone. Но это может обернуться и против вас. Тысячи запросов с одной и той же версией за короткие периоды?

Итак, следующий шаг – иметь и использовать несколько валидных и современных User-Agent. И чтобы список постоянно обновлялся. Как и в случае с IP-адресами, меняйте UA в каждом запросе вашего кода.

# ... same as above  user_agents = [      "Mozilla/5.0 (iPhone ...",      "Mozilla/5.0 (Windows ...",      # ... more User-Agents  ]   for url in urls:      proxy = random.choice(proxy_list)      proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}      response = requests.get(url, proxies=proxies)      print(response.text)

Исследуйте целевой контент

Взгляните на исходный код перед началом разработки. Многие сайты предлагают более удобные способы очистки данных, чем селекторы CSS.

Стандартный метод предоставления данных – использование расширенных сниппетов, например, с помощью JSON или атрибутов данных itemprop Schema.org. Другие используют скрытые входные данные для внутренних целей (например, идентификаторы, категории, код продукта), и вы можете воспользоваться этим. Это больше, чем кажется на первый взгляд.

veb skraping chto mozhno i chego nelzja delat 091c46e - Веб-скрапинг: что можно и чего нельзя делать

Некоторые сайты для получения данных полагаются на запросы XHR после первой загрузки. И эти данные структурированы!

Лучшее, что вы можете сделать, это просмотреть сайт в DevTools и проверить как HTML, так и вкладку Network. Так вы будете лучше понимать его структуру и сможете определить, как извлечь данные за несколько минут.

Эти приемы не всегда доступны, но их использование избавит вас от лишней головной боли. Метаданные, например, имеют тенденцию меняться реже, чем классы HTML или CSS, что делает их более надежными и удобными в обслуживании в долгосрочной перспективе.

veb skraping chto mozhno i chego nelzja delat f3b5323 - Веб-скрапинг: что можно и чего нельзя делать

Необходимо распараллеливать запросы

После масштабирования старого однофайлового последовательного скрипта будет недостаточно. Вероятно, вам придется выйти на «профессиональный» уровень. Для крошечной цели и нескольких URL-адресов может быть достаточно нескольких последовательных запросов. Но когда у вас тысячи запросов и разные домены, последовательные запросы не будут работать правильно.

Одним из первых шагов масштабирования было бы получение нескольких URL-адресов одновременно, а не прекращение всего скрапинга из-за медленного ответа. Переход от 50-строчного скрипта к масштабу Google – это гигантский скачок, но первые шаги достижимы. Главное, что вам понадобится: параллелизм и очередь.

Параллелизм

Основная идея – отправлять несколько запросов одновременно, но с ограничением. А потом, как только придет ответ, отправлять новый запрос. Допустим, предел — десять. Это означало бы, что десять URL-адресов всегда будут работать в любой момент времени, пока их больше не останется.

Очередь

Очередь – это структура данных, которая позволяет добавлять элементы для последующей обработки. Вы можете начать сканирование с одного URL, получить HTML и извлечь нужные ссылки. Добавьте их в очередь, и они начнут работать. Продолжайте делать то же самое, и вы создадите масштабируемого поискового робота. Конечно, может возникнуть проблема с бесконечными циклами или поворным сканированием одних и тех же страниц. Самый простой способ решить эту проблему – установить максимальное количество сканируемых страниц и останавливаться, как только доберетесь до него.

Все это еще далеко от масштаба Google, но с таким подходом вы можете перейти на тысячи страниц. Чтобы быть более точным, вы можете иметь разные настройки для каждого домена, чтобы избежать перегрузки одной цели.

Не используйте headless-браузеры повсеместно

Selenium, Puppeteer и Playwright, несомненно, великолепны, но это не панацея. Они увеличивают потребление ресурсов и замедляют веб-скрапинг. Так зачем же их использовать? Они точно нужны для содержимого, которое выводится при помощи JavaScript, и полезны во многих других ситуациях. Но спросите себя, нужны ли они именно в вашем случае.

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

В некоторых случаях вы не найдете информацию, потому что ее нет при первой загрузке, например, в Angular.io. Нет проблем, в таких случаях вам помогут headless-браузеры. Или XHR скрапинг (см. выше).

Если найдете информацию, попробуйте написать код для ее извлечения. Быстрого хака может быть достаточно для теста. После того, как вы определили весь нужный контент, следующим шагом будет отделить код общего краулинга от настраиваемого для целевого сайта.

  1. Использование requests в Python: 2,41 секунды.
  2. Playwright с chromium открывает новый браузер на каждый запрос: 11,33 секунды
  3. Playwright с chromium делит браузер и контекст для всех URL: 7,13 секунды

Эти данные не назовешь статистически точными, но они показывают разницу. В лучшем случае мы говорим о 3-кратном замедлении при использовании Playwright, да и совместное использование контекста не всегда является хорошей идеей. И мы даже не говорим о потреблении ресурсов процессора и памяти.

Не привязывайте код к цели

Некоторые действия не зависят от сайта, который вы скрапите: получить HTML, проанализировать его, поставить в очередь новые ссылки для сканирования, сохранить контент и многое другое. В идеале мы бы отделили те сценарии, которые зависят от целевого сайта: селекторы CSS, структуру URL, структуру DDBB.

Первый сценарий обычно запутан, но это не проблема. А вот по мере роста и добавления новых страниц разделение ответственности становится критически важным. Мы знаем: легче сказать, чем сделать. Но чтобы создать масштабируемый и поддерживаемый скрапер, имеет смысл притормозить и подумать немного. Разделите ваш код на части. Одна часть будет обслуживать общие для всех скраперов задачи, а другая будет подстраиваться под каждый сайт непосредственно.

Не «положите» целевой сайт

Нагрузка, которую вы создаете, может быть каплей в море для Amazon, но обузой для небольшого магазина. Помните о масштабе вашего скрапера и размере ваших целей.

Вероятно, вы можете сканировать сотни страниц на Amazon одновременно, и они даже не заметят этого (тем не менее, будьте осторожны). Но многие сайты работают на одной общей машине с не очень хорошими характеристиками, и к этому нужно относиться с пониманием. Уменьшите возможности скриптов для этих сайтов. Это может усложнить код, но было бы неплохо остановиться, если время отклика увеличится.

Другой момент – проверять и соблюдать их robots.txt. В основном есть два правила: не лезьте на запрещенные страницы и соблюдайте Crawl-Delay. С помощью этой директивы указывается количество секунд задержки между запросами поисковых роботов. Она встречается нечасто, но если есть — соблюдайте. Существует модуль Python, который может помочь обеспечить соответствие robots.txt.

Не будем вдаваться в подробности, но старайтесь не совершать преступлений. Когда мы обсуждаем веб-скрапинг, мы имеем в виду законную деятельность без нанесения ущерба целевому сайту.

Не смешивайте заголовки из разных браузеров

Этот последний метод касается высокоуровневых антиботов. Браузеры отправляют несколько заголовков с заданным форматом, который варьируется от версии к версии. А передовые решения проверяют их и сравнивают с реальной базой наборов заголовков. Таким образом, отправляя не те заголовки, вы будете поднимать красные флажки. Или, что еще труднее заметить, — не отправляя нужные!

Посетите httpbin, чтобы увидеть заголовки, отправляемые вашим браузером. Вероятно, их больше, чем вы представляете, а о некоторых вы даже не слышали!

Из этого нет простого выхода, кроме как иметь полный набор заголовков. Причем их должно быть много — по одному для каждого используемого вами User-Agent. Не один для Chrome, а другой для iPhone, нет.

По. Одному. На. Каждый. User-Agent.

Некоторые люди пытаются избежать этого, используя headless-браузеры, но мы уже говорили, почему это не волшебная пилюля. Кроме того, они отправляют весь набор заголовков, которые работают для этого браузера в этой версии. Если вы измените что-либо из набора, остальные заголовки могут оказаться невалидными.

Если вы используете Chrome с Puppeteer и перезапишете UA для использования iPhone UA, вас ждет сюрприз. Настоящий iPhone не отправляет «Sec-Ch-Ua», но Puppeteer отправит, поскольку вы перезаписали UA, но не удалили его.

Некоторые сайты предлагают список User-Agents. Но получить полные наборы для сотен UA сложно, а это необходимый масштаб при скрапинге сложных сайтов.

# ...   header_sets = [      {          "Accept-Encoding": "gzip, deflate, br",          "Cache-Control": "no-cache",          "User-Agent": "Mozilla/5.0 (iPhone ...",          # ...      }, {          "User-Agent": "Mozilla/5.0 (Windows ...",          # ...      },      # ... more header sets  ]   for url in urls:      # ...      headers = random.choice(header_sets)      response = requests.get(url, proxies=proxies, headers=headers)      print(response.text)

Мы знаем, что последний пункт тяжело реализовать. Но некоторые решения для защиты от скрапинга могут быть очень изобретательными, там могут быть не только заголовки. Кто-то может проверять отпечаток браузера или даже соединения – вещи высокого уровня.

Заключение

Итак, мы разобрали, что можно и чего нельзя делать при скрапинге веб-страниц. Чередование IP-адресов и наличие хороших заголовков позволят вам сканировать и скрапить большинство сайтов. Используйте headless-браузеры только при необходимости и применяйте передовые методы разработки программного обеспечения.

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

Масштабирование веб-скрапинга – сложный и долгий путь, но вам может и не понадобиться лучшая система. Не стоит добиваться стопроцентной точности. Если ваш скрапер работает на тех доменах, которые вам нужны, это уже достаточно хорошо!

Перевод статьи «DOs and DON’Ts of Web Scraping».

  • 4 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Связаться со мной
Close