Руководство по веб-скрапингу с помощью Java

В этом руководстве вы узнаете, как настроить проект Gradle и установить зависимость HtmlUnit. В процессе обучения вы узнаете все, что вам нужно знать о HtmlUnit, и изучите некоторые из его расширенных возможностей.
2 мин. чтения
Robotic arms coding on a computer screen.

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

 

Веб-скрапинг с помощью HtmlUnit

Для реализации веб-скрапинга с помощью HtmlUnit и Gradle будет использоваться IntelliJ IDEA, однако вы можете использовать любую другую IDE или редактор кода, который предпочитаете.

 

IntelliJ поддерживает полнофункциональную интеграцию с Gradle. IDE можно загрузить на сайте JetBrains. Gradle — инструмент автоматизации сборки, который поддерживает сборку и создание пакетов для вашего приложения. Он также позволяет легко добавлять и управлять зависимостями. В последней версии IntelliJ IDEA Gradle и его расширения установлены и включены по умолчанию.

 

Весь код для данного руководства можно найти в этом репозитории GitHub.

 

Создайте проект Gradle

Чтобы создать новый проект Gradle в IntelliJ IDE, выберите в меню File > New > Project, после чего откроется мастер создания нового проекта. Введите имя проекта и выберите его местоположение:

 

Вам необходимо выбрать язык Java, поскольку вы собираетесь создать приложение для веб-скрапинга на Java с использованием HtmlUnit. Кроме того, выберите систему сборки Gradle. Затем нажмите кнопку Create. В результате будет создан проект Gradle со структурой по умолчанию и всеми необходимыми файлами. Например, файл build.gradle содержит все зависимости, необходимые для сборки этого проекта:

 

Установите HtmlUnit

Чтобы установить HtmlUnit в качестве зависимости, откройте окно Dependencies, выбрав View > Tool Windows > Dependencies.

 

Затем найдите «htmlunit» и выберите Add:

 

Вы должны увидеть, что HtmlUnit был установлен в разделе зависимостей файла build.gradle:

 

Теперь, когда вы установили HtmlUnit, настало время собирать данные со статических и динамических веб-страниц.

Веб-скрапинг статической страницы

В этом разделе вы узнаете, как выполнить веб-скрапинг такой статической веб-страницы, как HtmlUnit Wiki. Она содержит такие элементы, как заголовок, оглавление, список подзаголовков и содержание каждого подзаголовка.

 

Каждый элемент веб-страницы HTML имеет различные атрибуты — например, ID или Name. Хотя оба из них используются для идентификации элемента в HTML-документе, Name, в отличие от ID, не обязательно является уникальным атрибутом и может принадлежать другим элементам веб-страницы. Элементы HTML-документа могут быть идентифицированы с помощью любого из атрибутов.

 

В качестве альтернативы вы можете использовать для идентификации элементов XPath. Помимо идентификации, он позволяет выполнять точную навигацию по DOM-элементам HTML-страницы.

 

В следующих примерах вы будете использовать для идентификации элементов HTML-страницы оба этих метода.

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

 

Чтобы инициализировать WebClient, используйте следующий код:

  WebClient webClient = new WebClient(BrowserVersion.CHROME);

Этот код инициализирует браузер Chrome. Другие браузеры также поддерживаются.

 

Получить веб-страницу можно с помощью метода getPage(), доступного в объекте webClient. Сделав это, вы с помощью разных методов можете извлекать из нее данные.

Чтобы получить заголовок страницы, используйте метод getTitleText(), как показано в следующем коде:

 

  String webPageURl = u0022https://en.wikipedia.org/wiki/HtmlUnitu0022;n        try {nn            HtmlPage page = webClient.getPage(webPageURl);n            n            System.out.println(page.getTitleText());n            n        } catch (FailingHttpStatusCodeException | IOException e) {n          n            e.printStackTrace();n            n        }

Затем будет напечатан заголовок страницы:

  HtmlUnit - Wikipedia

А теперь давайте извлечем все имеющиеся на веб-странице H2-элементы. В данном случае они есть всего в двух разделах:

  1. В левом сайдбаре, где отображается контент: Как видите, заголовок раздела Contents является H2-элементом.

     

  2. В основном теле страницы: Все подзаголовки являются H2-элементами.

Чтобы получить все H2-элементы веб-страницы, можно воспользоваться их XPath. Чтобы найти XPath, щелкните правой кнопкой мыши на нужном H2-элементе и выберите Inspect. Затем щелкните правой кнопкой мыши на выделенном элементе и выберите Copy > Copy full XPath:

 

Это скопирует XPath в буфер обмена. Например, XPath H2-элемента внутри тега body — /html/body/div[1]/div/div[3]/main/div[2]/div[3]/div[1]/h2.

 

Чтобы получить все H2-элементы с помощью их XPath, можно использовать метод getByXpath():

 

  String xPath = u0022/html/body/div[1]/div/div[3]/main/div[2]/div[3]/div[1]/h2u0022;nn String webPageURL = u0022https://en.wikipedia.org/wiki/HtmlUnitu0022;n n        try {n            HtmlPage page = webClient.getPage(webPageURL);nn            //Get all the headings using its XPath+n            Listu003cHtmlHeading2u003e  h2 = (Listu003cHtmlHeading2u003e)(Object) page.getByXPath(xPath);n            n            //print the first heading text contentn            System.out.println((h2.get(0)).getTextContent());nn        } catch (FailingHttpStatusCodeException | IOException e) {n          n            e.printStackTrace();n            n        }

Текстовое содержимое первого H2-элемента будет выведено следующим образом:

  Benefits[edit]

Аналогично, вы можете получить элементы по их ID с помощью метода getElementById() , или же по их имени благодаря методу getElementByName().

 

В следующем разделе вы будете использовать эти методы для скрапинга динамической веб-страницы.

Скрапинг динамической веб-страницы с помощью HtmlUnit

В этом разделе вы познакомитесь с возможностями HtmlUnit по заполнению форм и нажатию кнопок, заполнив и отправив форму для входа в систему. Вы также узнаете, как с помощью этого браузера перемещаться по веб-страницам.

Чтобы продемонстрировать динамический веб-скрапинг, давайте воспользуемся сайтом Hacker News. Вот как выглядит страница для входа в систему:

 

Следующий код — это HTML-форма для предыдущей страницы. Вы можете получить его, щелкнув правой кнопкой мыши по ярлыку Login Label и выбрав Inspect:

 

  u003cform action=u0022loginu0022 method=u0022postu0022u003enu003cinput type=u0022hiddenu0022 name=u0022gotou0022 value=u0022newsu0022u003enu003ctable border=u00220u0022u003enu003ctbodyu003enu003ctru003eu003ctdu003eusername:u003c/tdu003eu003ctdu003eu003cinput type=u0022textu0022 name=u0022acctu0022 size=u002220u0022 autocorrect=u0022offu0022 spellcheck=u0022falseu0022 autocapitalize=u0022offu0022 autofocus=u0022trueu0022u003eu003c/tdu003eu003c/tru003enu003ctru003eu003ctdu003epassword:u003c/tdu003eu003ctdu003eu003cinput type=u0022passwordu0022 name=u0022pwu0022 size=u002220u0022u003eu003c/tdu003eu003c/tru003eu003c/tbodyu003eu003c/tableu003eu003cbru003enu003cinput type=u0022submitu0022 value=u0022loginu0022u003eu003c/formu003e

Чтобы заполнить форму с помощью HtmlUnit, получите веб-страницу с помощью объекта webClient. Страница содержит две формы: Login и Create Account. Форму для входа можно получить благодаря методу getForms().get(0). В качестве альтернативы разрешается использовать метод getFormByName(), если формы имеют уникальное имя.

 

Далее необходимо получить входные данные (имя пользователя и пароль) с помощью метода getInputByName() и атрибута name.

 

Установите имя пользователя и пароль в соответствующие поля с помощью метода  setValueAttribute()  и получите кнопку Submit, используя для этого метод  getInputByValue(). Нажать на нее можно благодаря методу  click().

 

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

 

Следующий код демонстрирует, как получить форму, заполнить ее и отправить:

  HtmlPage page = null;nnString webPageURl = u0022https://en.wikipedia.org/wiki/HtmlUnitu0022;nn        try {n            // Get the first pagenn            HtmlPage signUpPage = webClient.getPage(webPageURL);nn            // Get the form using its index. 0 returns the first form.n            HtmlForm form = signUpPage.getForms().get(0);nn            //Get the Username and Password field using its namen            HtmlTextInput userField = form.getInputByName(u0022acctu0022);n            HtmlInput pwField = form.getInputByName(u0022pwu0022);n            n            //Set the User name and Password in the appropriate fieldsn            userField.setValueAttribute(u0022draftdemoacctu0022);n            pwField.setValueAttribute(u0022test@12345u0022);nn            //Get the submit button using its Valuen            HtmlSubmitInput submitButton = form.getInputByValue(u0022loginu0022);nn            //Click the submit button, and it'll return the target page of the submit buttonn            page = submitButton.click();nnn        } catch (FailingHttpStatusCodeException | IOException e) {n            e.printStackTrace();n        }

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

Элемент имени пользователя имеет идентификатор (ID) «me». Вы можете получить имя пользователя с помощью метода getElementById() и передать идентификатор «me», как показано в следующем коде:

 

  System.out.println(page.getElementById(u0022meu0022).getTextContent());

Имя пользователя извлекается из веб-страницы и выводится:

  draftdemoacct

Далее необходимо перейти на вторую страницу сайта Hacker News, нажав на кнопку More в конце страницы:

 

Чтобы получить объект кнопки More, найдите XPath кнопки More, используя опцию Inspect, и отыщите объект первой ссылки, используя индекс 0:

 

Кликните по ссылке More с помощью метода click(). Благодаря его использованию целевая страница ссылки будет возвращена в виде объекта HtmlPage:

 

  HtmlPage nextPage = null;nn        try {n            Listu003cHtmlAnchoru003e links = (Listu003cHtmlAnchoru003e)(Object)page.getByXPath(u0022html/body/center/table/tbody/tr[3]/td/table/tbody/tr[92]/td[2]/au0022);n            n            HtmlAnchor anchor =  links.get(0);n            n            nextPage = anchor.click();nn        } catch (IOException e) {n            throw new RuntimeException(e);n        }

На этом этапе у вас должна быть вторая страница в объекте HtmlPage.

 

Вы можете вывести URL HtmlPage, чтобы проверить, успешно ли загружена вторая страница:

 

  System.out.println(nextPage.getUrl().toString());

Ниже приведен URL второй страницы:

  https://news.ycombinator.com/news?p=2

Каждая страница сайта Hacker News содержит тридцать записей. Поэтому записи на второй странице начинаются с порядкового номера 31.

Давайте получим ID первой записи на второй странице и посмотрим, равна ли она 31. Как и ранее, найти XPath первой записи можно с помощью опции Inspect.

Затем возьмите первую запись из списка и отобразите ее текстовое содержимое:

 

  String firstItemId = null;nn        Listu003cObjectu003e entries = nextPage.getByXPath(u0022/html/body/center/table/tbody/tr[3]/td/table/tbody/tr[1]/td[1]/spanu0022);nn        HtmlSpan span = (HtmlSpan) (entries.get(0));nn        firstItemId = span.getTextContent();n        n        System.out.println(firstItemId);

Теперь отображается идентификатор (ID) первой записи:

  31.

Этот код показывает, как заполнять форму, нажимать на кнопки и перемещаться по веб-страницам с помощью HtmlUnit.

Заключение

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

При работе с IDE, например IntelliJ IDEA, необходимо вручную находить атрибуты элементов, а затем с нуля прописывать использующие их функции веб-скрапинга. Для сравнения, Web Scraper IDE от Bright Data предоставляет легко обходящую любые гео-ограничения и блокировки надежную прокси-инфраструктуру, удобные функции веб-скрапинга и готовые шаблоны кода для популярных веб-сайтов. Эффективная прокси-инфраструктура — жизненно необходима для веб-скрапинга без каких-либо проблем с блокировкой IP-адресов и ограничением скорости. Использование прокси также помогает эмулировать пользователей с разной геолокацией.