2 техники для парсинга Ajax-тяжелых веб-сайтов с использованием Selenium и Chromedriver
Большинство учебников по парсингу, которые вы найдете в Интернете, сосредоточены на инструментах, которые могут получать веб-страницы и анализировать содержимое HTML. Это отлично работает для обычных веб-сайтов с запросами-ответами, где каждая страница находится по отдельному URL. Однако все больше данных, которые вы хотите спарсить, будут размещены на сайтах, которые загружают контент с сервера через Ajax и используют такие методы, как бесконечная прокрутка, чтобы страница никогда не перезагружалась, но новые данные передаются с сервера.
Один из вариантов, конечно, - попытаться обратно разработать API-вызовы, получающие данные с сервера. Однако это занимает много времени, и перед вами стоят множество преград, таких как токены авторизации и криптографические методы разбиения на страницы.
В процессе такой задачи недавно я задумался: "Почему это так трудно, все данные передаются в мой браузер, если бы я мог их просто перехватить". Именно это привело меня к долгому поиску на Stack Overflow и, в конечном итоге, к двум техникам, которые сделали мою задачу намного проще.
Первое открытие заключалось в том, чтобы отказаться от методов, которые делают отдельные запросы для получения страниц, таких как Mechanize, и вместо этого использовать полноценный браузер для обхода сайтов с помощью Selenium.
Что такое Selenium?
Selenium - это фреймворк для автоматизации браузеров, в основном для тестирования, но его также можно использовать и для других целей. Selenium подключается к нескольким различным браузерам, таким как Firefox и Chrome. Я использовал Chrome, потому что с ним я наиболее знаком, и примеры, которые я нашел в Интернете, использовали его.
С помощью Selenium я теперь могу загрузить страницу с бесконечной прокруткой и использовать JavaScript для прокрутки вниз по странице, загружая новые данные. Вот небольшой пример на Ruby:
# Код примера на Ruby
Но это была только часть решения. Теперь я могу видеть все, что загружено в DOM, однако много информации скрыто до тех пор, пока пользователь не взаимодействует с ней, и может не быть частью дерева DOM до тех пор, пока взаимодействие не произойдет. Это особенно верно для современных JS-фреймворков, таких как React.
В теории вы можете попытаться имитировать все взаимодействия пользователя через браузер, но к счастью есть более простой способ!
Перехват Ajax-запросов
Все данные, которые могут быть отображены, загружаются через Ajax, так что что, если мы перехватим Ajax-запросы? К счастью, я наткнулся на эту статью на Stack Overflow, где описывается, как сделать именно это. Внедряя JS, подобным образом, вы можете получить все Ajax-запросы, записанные в переменную, которую вы сможете получить позже.
(Благодаря этой статье на Stack Overflow за подсказку о driver.send(:bridge)
)
Теперь у вас есть все ответы XHR в удобном массиве для дальнейшего анализа.
Что насчет изображений и видео?
Этот последний метод хорошо работает для Ajax-запросов, но что, если вы хотите узнать все URL-адреса видео, которые загружает страница? Опять же, Chromedriver приходит на помощь.
Chromedriver предоставляет доступ через JavaScript к инструментам мониторинга производительности Chrome, включая список всех URL-адресов, загруженных страницей, их размеры файлов и другую информацию. Вы можете получить к нему доступ следующим образом:
var performanceEntries = window.performance.getEntries();
Выполнение этого кода после выполнения некоторых действий на странице вернет массив, содержащий пары URL-адресов и размеров файлов. Вы можете экспериментировать, чтобы узнать, что еще это предоставляет вам. Если вы находитесь в Chrome, вы можете прямо сейчас открыть консоль браузера и получить доступ к performance.getEntries()
.
Используя эту информацию, вы можете, например, загрузить все миниатюры на сайте с бесконечной прокруткой или получить URL-адрес видеопотока для видео, воспроизводимого где-то на странице.
Заключение
Надеюсь, это даст вам новые идеи о том, как вы можете использовать Selenium + Chromedriver для парсинга веб-сайтов с большим количеством Ajax-запросов!