Веб-скрапинг - это термин, обычно используемый для использования автоматизированного метода извлечения данных с веб-сайта. В случаях, когда веб-сайт не предоставляет API, использование веб-скрейпинга для извлечения содержащихся в нем данных иногда является единственным способом программного доступа к их контенту. Имейте в виду, что веб-очистка веб-сайта может противоречить их условиям обслуживания, поэтому обязательно проверьте их в первую очередь.
В этой статье мы хотим дать вам краткое введение в парсинг веб-страниц и показать вам, как этого можно добиться с помощью Ruby.
Как работает парсинг?
На первый взгляд, веб-очистка очень проста. Вы начинаете с загрузки веб-сайта в свой браузер, а затем с помощью инструментов разработчика можете анализировать структуру контента. Веб-сайты обычно имеют предсказуемую структуру, идентификаторы и имена классов, которые могут позволить вам точно определять различные элементы на сайте. Возьмем, к примеру, этот фрагмент HTML, который отображает таблицу цен:
<div class="card-deck mb-3 text-center"> <div class="card mb-4 shadow-sm"> <div class="card-header"> <h4 class="my-0 font-weight-normal">Free</h4> </div> <div class="card-body"> <h1 class="card-title pricing-card-title">$0 <small class="text-muted">/ mo</small></h1> <ul class="list-unstyled mt-3 mb-4"> <li>10 users included</li> <li>2 GB of storage</li> <li>Email support</li> <li>Help center access</li> </ul> <button type="button" class="btn btn-lg btn-block btn-outline-primary">Sign up for free</button> </div> </div> <div class="card mb-4 shadow-sm"> <div class="card-header"> <h4 class="my-0 font-weight-normal">Pro</h4> </div> <div class="card-body"> <h1 class="card-title pricing-card-title">$15 <small class="text-muted">/ mo</small></h1> <ul class="list-unstyled mt-3 mb-4"> <li>20 users included</li> <li>10 GB of storage</li> <li>Priority email support</li> <li>Help center access</li> </ul> <button type="button" class="btn btn-lg btn-block btn-primary">Get started</button> </div> </div> </div>
Вы можете перебрать все элементы, которые имеют класс .card
, чтобы получить обе ценовые карты, а затем в каждом из них вы можете получить имя плана с помощью класса .card-header
. Используя li
элементы, вы даже можете получить характеристики плана. Сделаем это на Ruby:
require 'nokogiri' # The whole document html = '<div class="card-deck mb-...' # create a Nokogiri document doc = Nokogiri::HTML(html) # Get all the plan names doc.css('.card').map { |card| card.css('.card-header h4').text } # => ["Free", "Pro"] # Get structured data doc.css('.card').map do |card| title = card.css('.card-header h4').text price = card.css('.card-body .pricing-card-title').text features = card.css('.card-body ul li').map do |feature| feature.text end { title: title, price: price, features: features } end # => [{:title=>"Free", # :price=>"$0 / mo", # :features=> # ["10 users included", # "2 GB of storage", # "Email support", # "Help center access"]}, # {:title=>"Pro", # :price=>"$15 / mo", # :features=> # ["20 users included", # "10 GB of storage", # "Priority email support", # "Help center access"]}]
Мы используем Nokogiri, отличную библиотеку для синтаксического анализа XML / HTML-документов в Ruby (подробнее об этом позже). В первой выделенной строке загружаем документ в Нокогири. Затем во второй выделенной строке мы извлекаем названия планов. Мы делаем это, перебирая все элементы с помощью класса CSS .card
, как мы обсуждали выше. В последнем выделенном блоке мы идем немного дальше и извлекаем заголовок, цену и все функции. Используя разные селекторы CSS, вы можете получить из документа практически все, что захотите.
Различные методы и динамический контент
Существует множество различных методов очистки веб-страниц. Все зависит от ваших потребностей и от того, как форматируются данные. Нет ничего необычного в том, чтобы прибегать к комбинации способов рендеринга и последующего анализа данных. Например, с простой веб-страницы, такой как моя, очень легко извлечь данные, потому что у нее простая структура и нет ничего динамического. Сравните это, например, с веб-сайтом Facebook, где много динамического контента, и вы столкнулись с очень сложной проблемой извлечения данных.
<html lang="en"> <head> <title>Single Page Application</title> </head> <body> <div id="app"></div> <script src="https://example.org/some-framework.js"></script> <script> MyFramework.start(document.getElementById('app')); </script> </body> </html>
Особенность динамических веб-сайтов (также называемых одностраничными приложениями) заключается в том, что HTML-код, который отображается первым, обычно почти пустой. За кулисами скрывается Javascript, который загружает фреймворк и выполняет некоторые сетевые запросы, которые в конечном итоге визуализируют контент. В таких ситуациях вам понадобится что-то вроде браузера для визуализации веб-сайта, и только тогда вы сможете начать извлечение данных. Взгляните, например, на приведенный выше фрагмент: нет контента! Это связано с тем, что всю тяжелую работу будет выполнять сам фреймворк.
Безголовый Chrome и прокси
Одним из решений проблемы, описанной выше, является использование реального веб-браузера для получения содержимого. Если бы вы получили такой веб-сайт с помощью cURL
, вы просто получили бы этот (почти) пустой документ. Вы можете открыть свой браузер и загрузить веб-сайт, скопировать обработанный HTML-код из инструментов разработчика и проанализировать его, но в какой-то момент вам нужно будет автоматизировать этот процесс. Здесь на помощь приходят такие инструменты, как Headless Chrome. Headless Chrome позволяет вам управлять экземпляром Chrome программно, без необходимости открывать окно с полным пользовательским интерфейсом (отсюда «безголовый»). Поскольку это полноценный браузер, вы получаете все функции, в частности рендеринг окончательного размера, который вам нужен.
При парсинге веб-сайтов также возникает проблема с тем, откуда идет соединение. Если вы настроили сервер для извлечения некоторых данных с веб-сайта, вы, скорее всего, начнете достигать ограничений по скорости. Это означает, что вам придется либо очень медленно добывать данные с целевого веб-сайта, либо вообще не иметь возможности. Одно из решений - использовать прокси. Использование прокси-сервера позволит вам сбалансировать ваши запросы между несколькими исходными местоположениями, чтобы избежать ограничения скорости. Разумеется, вы всегда должны помнить об условиях использования веб-сайта.
Одним из таких прокси-сервисов является ScrapingBee, который выполняет обе эти функции: безголовое хромирование и проксирование. И их услуги доступны в RapidAPI, поэтому начать работу очень просто.
Давай поскребем что-нибудь!
Мы создадим простой парсер, который будет использовать ScrapingBee для рендеринга веб-сайта и проксирования соединения. Для этого вам понадобятся:
- "Рубин",
- Жемчужина нокогири,
- Исключительный драгоценный камень,
- Учетная запись RapidAPI
Чтобы установить Ruby, обратитесь к их официальному руководству по установке. Еще нам понадобится Нокогири. Этот гем, как вы видели ранее, позволяет с легкостью анализировать и извлекать данные из HTML-документов. Его установка немного сложна и действительно зависит от вашей платформы. Таким образом, мы также хотели бы отослать вас к их руководствам по установке, которые укажут вам правильное направление относительно того, как их установить. Если вы можете запустить gem install nokogiri
в своем терминале без ошибок, все будет в порядке. Также убедитесь, что вы установили Excon, запустив gem install excon
.
Чтобы получить свою учетную запись RapidAPI, просто зайдите на rapidapi.com и зарегистрируйтесь. У ScrapingBee API есть уровень бесплатного использования, но для этого в любом случае требуется настроить кредитную карту. В любом случае вам не нужно платить ни за что, что мы делаем в этом руководстве, поскольку их бесплатный план достаточно велик.
Настроить ScrapingBee
Перейдите на страницу ScrapingBee в RapidAPI и нажмите кнопку Подписаться для получения бесплатного плана. При необходимости введите данные своей кредитной карты.
После этого перейдите на вкладку Конечные точки и возьмите свой хост и ключ API. Они показаны как X-RapidAPI-Host
и X-RapidAPI-Key
соответственно. И то, и другое вам понадобится в следующих разделах.
Извлечение данных API с веб-сайта RapidAPI
В качестве примера того, что вы можете делать с помощью ScrapingBee и Ruby, мы извлечем список API из RapidAPI. Давайте сначала посмотрим, как мы можем извлечь некоторые основные данные. Если мы перейдем на Rapidapi.com и нажмем на категорию слева, вы попадете в список API. Это список, на который мы будем ориентироваться.
Если вы используете Chrome, вы можете щелкнуть элемент правой кнопкой мыши и выбрать «Проверить». Это открывает инструменты разработчика и позволяет вам легко видеть селекторы CSS, которые вы можете использовать для извлечения того, что вам нужно. В нашем случае использование класса ApiItemstyled__ResponsiveWrapper-qvgmn9-8
дает нам все API, отображаемые в представлении категории. Используя класс ApiItemstyled__ApiItemWrapperName-qvgmn9-2
, мы можем извлечь имя API. Описание можно получить с помощью класса ApiItemstyled__Description-qvgmn9-4
, а с помощью класса ApiItemstyled__Footer-qvgmn9-5
мы можем получить статистику внизу, например, популярность. Напишем код:
View full code at https://rapidapi.com/blog/web-scraping-ruby/
Убедитесь, что вы используете инструменты разработчика в своем браузере, чтобы вы могли следить за тем, как мы здесь используем селекторы CSS. В первом выделенном блоке мы делаем запрос к ScrapingBee через RapidAPI. Мы указываем render_js
на true
, чтобы наш экземпляр безголового Chrome отображал веб-сайты Javascript. Далее мы разбираем ответ с помощью Nokogiri. Наконец, мы захватываем все элементы API на странице, перебираем их и извлекаем из них заголовок, описание и статистику. Обратите особое внимание на то, как мы получаем статистику. (Очень упрощенный) HTML выглядит так:
<div class="ApiItemstyled__Footer-qvgmn9-5 kTwcIW"> <div> <div class="FlexLayouts__FlexRowCenterCenter-sc-1j19v2f-8 jlDTbN"> <img src="/static-assets/default/popularity.svg"> <div class="ApiItemstyled__FooterItem-qvgmn9-6 dzVIkT">9.9</div> </div> </div> <div> <div class="FlexLayouts__FlexRowCenterCenter-sc-1j19v2f-8 jlDTbN"> <img src="/static-assets/default/latency.svg"> <div class="ApiItemstyled__FooterItem-qvgmn9-6 dzVIkT">170ms</div> </div> </div> <div> <div class="FlexLayouts__FlexRowCenterCenter-sc-1j19v2f-8 jlDTbN"> <img src="/static-assets/default/success-new.svg"> <div class="ApiItemstyled__FooterItem-qvgmn9-6 dzVIkT">83%</div> </div> </div> </div>
Итак, мы берем все третьи div из элемента с именем класса ApiItemstyled__Footer-qvgmn9-5
. Затем мы сопоставляем этот массив результатов и получаем текст из каждого элемента. Теперь, после запуска нашего скрипта, мы получаем массив примерно такого вида:
[{:title=>"City Geo-Location Lookup", :description=> "This API gives you Latitude, Longitude, Time-Zone of any city", :popularity=>"9.8", :latency=>"1492ms", :success=>"94%"}, {:title=>"Get Video and Audio URL", :description=> "Get direct links to download video or audio files from almost any hosting website, like Youtube, Twitch, SoundCloud, etc with download api.", :popularity=>"9.8", :latency=>"6977ms", :success=>"99%"}, {:title=>"Currency Exchange", :description=> "Live currency and foreign exchange rates by specifying source and destination quotes and optionally amount to calculate. Support vast amount of quotes around the world.", :popularity=>"9.8", :latency=>"1347ms", :success=>"96%"}, # and more... ]
Выводы и подсказки
Мы надеемся, что это дало вам представление о том, как лучше всего использовать парсинг веб-страниц. Вот несколько советов, которые сделают путешествие немного проще:
- Протестируйте селекторы CSS в браузере: используя что-то вроде
document.querySelectorAll()
, вы можете протестировать свои селекторы CSS и убедиться, что они действительно выбирают то, что вам нужно, а не больше. - Некоторым веб-сайтам может потребоваться какое-то взаимодействие для загрузки всего. Например, вам нужно прокрутить, чтобы запустить загрузчик с бесконечной прокруткой. В этом случае можно отправить код Javascript, который может быть выполнен в автономном экземпляре Chrome. Просто убедитесь, что он закодирован в Base64.
- Если вам нужно, чтобы ScrapingBee подождал несколько секунд перед отправкой вам содержимого веб-сайта (например, веб-сайту требуется больше времени, чем обычно для рендеринга), вы можете отправить дополнительный параметр с именем
wait
, в котором вы можете указать до 10 000 миллисекунд время ожидания.
Связанные ресурсы
- Как использовать API с Ruby
- Использование Ruby и RapidAPI
- Лучшие фреймворки Ruby
- Как использовать Amazon API с Ruby
Первоначально опубликовано на https://rapidapi.com 16 декабря 2019 г.