перейти к содержанию

Полное руководство по парсингу веб-сайтов JavaScript с помощью Scrapy и Splash

За последнее десятилетие JavaScript стал повсеместным в сети. Все большее число сайтов теперь полагаются на JavaScript для динамического отображения контента на стороне клиента, а не на стороне сервера. Это создает проблему для веб-скраперов. Традиционные инструменты, такие как Beautiful Soup и Scrapy, могут очищать только статический HTML-код, передаваемый с сервера. Чтобы парсить динамические сайты JavaScript, нам нужен безголовый браузер. Вот здесь-то и появляется Всплеск…

Распространение веб-приложений на JavaScript

Использование JavaScript с годами резко возросло:

  • 97% веб-сайтов сейчас используют JavaScript на стороне клиента (W3Techs)
  • 94% из 10,000 XNUMX лучших сайтов используют такие платформы JavaScript, как React, Angular и Vue (реагировать)

Этот сдвиг обусловлен популярностью веб-фреймворков, таких как React, Angular и Vue, во внешнем интерфейсе. Эти платформы динамически отображают контент в браузере с помощью JavaScript, а не полагаются исключительно на серверные шаблоны.

Для очистки этих современных веб-приложений JavaScript требуется браузер для выполнения JavaScript. Такие инструменты, как запросы и Beautiful Soup, здесь не справляются. Вместо этого нам нужен инструмент автоматизации браузера, такой как Selenium, Playwright или Splash.

Почему Splash меняет игру

Splash — это служба рендеринга JavaScript с HTTP API для управления браузером. Splash, разработанный Scrapinghub, прекрасно интегрируется со Scrapy, предоставляя возможности автоматизации браузера, необходимые для очистки динамических сайтов JavaScript.

Вот некоторые ключевые преимущества Splash:

Безголовый браузер – Splash использует веб-кит из браузера Chromium, но работает без видимого пользовательского интерфейса. Это делает его идеальным для парсинга на стороне сервера.

Быстрый и легкий – Splash потребляет гораздо меньше ресурсов процессора и памяти, чем Selenium или Puppeteer. Он создан для обеспечения высокой производительности в любом масштабе.

Сценарий – Скрипты Lua можно использовать для эмуляции сложных действий пользователя, таких как прокрутка, нажатие, отправка форм и т. д.

Scrapy-интеграция – Промежуточное программное обеспечение Splash упрощает использование Scrapy. Это похоже на использование обычных запросов Scrapy.

Распределенное сканирование – Splash прекрасно сочетается с кластеризацией Scrapy для распределенного сканирования. Горизонтальное масштабирование легко.

В целом, Splash предоставляет возможности динамического рендеринга, необходимые для сайтов JavaScript, в быстром, легком и поддерживающем сценарии пакете, который легко интегрируется со Scrapy для крупномасштабного распределенного парсинга.

Установка Всплеска

Splash доступен в виде образа Docker, что упрощает настройку. Его также можно установить на Linux и macOS без Docker.

Сначала убедитесь, что Docker установлен в вашей системе.

Затем извлеките образ Splash Docker из Docker Hub:

docker pull scrapinghub/splash

Загрузив образ, запустите экземпляр Splash на порту 8050:

docker run -p 8050:8050 scrapinghub/splash

Теперь Splash будет запущен в контейнере и готов к очистке! Splash REPL доступен для тестирования через порт 8050.

Интеграция Splash со Scrapy

Чтобы вызвать Splash из пауков Scrapy, мы воспользуемся командой scrapy-splash библиотека, которая хорошо справляется с интеграцией.

Сначала установите Scrapy и Scrapy-splash:

pip install scrapy scrapy-splash

Затем включите промежуточное программное обеспечение Splash и фильтр dupefilter в settings.py:

SPLASH_URL = ‘http://localhost:8050‘

DOWNLOADER_MIDDLEWARES = {
    ‘scrapy_splash.SplashCookiesMiddleware‘: 723,
    ‘scrapy_splash.SplashMiddleware‘: 725,
}

DUPEFILTER_CLASS = ‘scrapy_splash.SplashAwareDupeFilter‘ 

Это настраивает Scrapy для отправки запросов через локальный экземпляр Splash.

Парсинг с помощью SplashRequest

Чтобы отправлять запросы в Splash, а не сканировать напрямую, Scrapy предоставляет SplashRequest класса.

from scrapy_splash import SplashRequest

def start_requests(self):

  yield SplashRequest(
    url="http://quotes.toscrape.com", 
    callback=self.parse,
    args={‘wait‘: 0.5},
  )

def parse(self, response):
  # Extract quotes from response.body

Ассоциация args параметр позволяет отправлять конфигурацию в Splash, например wait времени.

Splash визуализирует JavaScript и возвращает результат HTML нашему parse обратный вызов, где мы можем извлечь данные, как обычно, с помощью Scrapy Selectors.

Обработка пагинации на основе JavaScript

Одним из преимуществ использования Splash является то, что он может нажимать ссылки и кнопки, которые обрабатывает JavaScript. Например, давайте очистим сайт, используя бесконечную прокрутку страниц, как в Twitter.

Без Splash мы не смогли бы запустить загрузку дополнительных страниц. Но с помощью сценариев Splash Lua мы можем автоматизировать прокрутку для загрузки большего количества контента:

script = """
  function main(splash)
    splash:go(splash.args.url)

    while not splash:select(‘.loading‘) do
         splash:runjs(‘window.scrollBy(0, 1000)‘)
         splash:wait(1)
    end

    return splash:html()
  end
"""

def start_requests(self):

  yield SplashRequest(
    url="https://twitter.com/elonmusk",
    callback=self.parse,
    args={
      ‘lua_source‘: script
    }
  )

def parse(self, response):
  # Extract Tweets

Этот скрипт постепенно прокручивается вниз до тех пор, пока не исчезнет индикатор загрузки, расширяя фрагмент страницы, доступный Scrapy.

Обработка reCAPTCHA с помощью Splash

Сайты с большим количеством JavaScript часто используют reCAPTCHA и другие меры защиты от ботов. Splash позволяет обойти эту защиту, автоматизируя браузер для решения проблем.

Например, мы можем создать скрипт для автоматического нажатия reCAPTCHA:

script = """
  function main(splash)

    -- Go to target url
    splash:go(splash.args.url)

    -- Wait for reCAPTCHA to load
    splash:wait(5)

    -- Click on reCAPTCHA checkbox
    splash:runjs(‘document.getElementById("recaptcha-anchor").click()‘)

    -- Wait for validation
    splash:wait(10)

    return splash:html()
  end
"""

Таким образом, Splash может пройти первоначальный шлюз reCAPTCHA, который мешает другим парсерам. Конечно, защита от ботов постоянно развивается, поэтому парсеры необходимо постоянно поддерживать и обновлять, чтобы адаптироваться.

Советы по отладке

Вот несколько советов по отладке пауков Scrapy с помощью Splash:

  • Проверьте информацию о запросе/ответе Splash в журналах Scrapy.
  • Проверьте необработанный HTML-ответ на http://localhost:8050/render.html
  • Включить подробный вход в систему Splash settings.py
  • Используйте инструменты разработчика браузера для устранения проблем JS
  • Замедлить темп с args={‘wait‘: 3} изолировать проблемы
  • Установить аргумент Splash images=0 отключить загрузку ресурсов
  • Используйте splash:go() в сценариях Lua для перезапуска рендеринга
  • Перехват и обработка распространенных исключений SplashScriptError.

Тщательный мониторинг журналов при возникновении проблем помогает сузить круг проблем.

Лучшие практики для производства

Вот несколько советов по парсингу сайтов JavaScript в больших масштабах:

  • Используйте надежную службу ротации прокси, например Oxylabs, чтобы избежать блокировки IP-адресов.
  • Внедрите случайные задержки от 2 до 10 секунд для ваших пауков.
  • Распределите рабочие файлы Scrapyd по множеству серверов.
  • Оптимизируйте настройку Docker с помощью docker-compose для кластеров Splash.
  • Включите кэширование и сохранение Scrapy для меньшего количества запросов Splash.
  • Отслеживайте узкие места производительности и соответствующим образом масштабируйте ресурсы.

Избегайте взрывов как можно быстрее, чтобы оставаться вне поля зрения. Медленное, равномерное и распределенное сканирование снижает риск.

Парсинг сложных сайтов – пример GitHub

Давайте рассмотрим пример очистки профилей GitHub, который в значительной степени использует JavaScript для навигации и объединения данных из вызовов API.

Сначала несколько примеров страниц профиля:

Код паука:

import json
from scrapy_splash import SplashRequest

class GithubSpider(scrapy.Spider):

  # Other spider code...

  def start_requests(self):

    profiles = [
      ‘https://github.com/scrapy/‘,
      ‘https://github.com/tensorflow‘ 
    ]

    for url in profiles:
      yield SplashRequest(url, self.parse, endpoint=‘render.html‘)

  def parse(self, response):

    # Extract profile info from HTML
    yield {
      ‘name‘: response.css(‘name‘).get(),
      ‘bio‘: response.css(‘bio‘).get(),
      # etc...
    }

    # Extract additional JSON data
    json_data = json.loads(response.css(‘json-data‘).get()) 
    yield {
      ‘public_repos‘: json_data[‘public_repos‘],
      ‘followers‘: json_data[‘followers‘]
    }

Ключевые моменты:

  • Используйте render.html а не по умолчанию execute конечная точка для возврата HTML
  • GitHub встраивает данные JSON, которые мы можем анализировать напрямую.
  • Сценарии Lua также могут помочь очистить дополнительные страницы.

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

Подводя итог

Веб-приложения с большим количеством JavaScript становятся нормой. Скребки, созданные на основе BeautifulSoup и Requests, больше не справляются с этой задачей. Splash устраняет этот пробел, предоставляя простой HTTP API для управления безголовым рендерингом браузера.

Splash, интегрированный со Scrapy, позволяет динамически очищать даже сложные веб-приложения JavaScript в любом масштабе. Такие функции, как создание сценариев, обеспечивают контроль, необходимый для эмуляции действий пользователя для разбивки на страницы и защиты от ботов.

Чтобы работать с веб-приложениями следующего поколения, каждому инструменту парсера необходим мощный инструмент рендеринга JavaScript, такой как Splash.

Присоединяйтесь к беседе

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