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-элементы. В данном случае они есть всего в двух разделах:
- В левом сайдбаре, где отображается контент: Как видите, заголовок раздела Contents является H2-элементом.
- В основном теле страницы: Все подзаголовки являются 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()
, или же по их имени благодаря методу getElementBy
Name
().
В следующем разделе вы будете использовать эти методы для скрапинга динамической веб-страницы.
Скрапинг динамической веб-страницы с помощью 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-адресов и ограничением скорости. Использование прокси также помогает эмулировать пользователей с разной геолокацией.