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

В этом руководстве вы узнаете, как настроить проект Gradle и установить зависимость HtmlUnit. В процессе обучения вы узнаете все, что вам нужно знать о HtmlUnit, и изучите некоторые из его расширенных возможностей.
3 min read
Web Scraping with Java Guide_large

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 = "https://en.wikipedia.org/wiki/HtmlUnit";
        try {

            HtmlPage page = webClient.getPage(webPageURl);
            
            System.out.println(page.getTitleText());
            
        } catch (FailingHttpStatusCodeException | IOException e) {
          
            e.printStackTrace();
            
        }

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

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 = "/html/body/div[1]/div/div[3]/main/div[2]/div[3]/div[1]/h2";

 String webPageURL = "https://en.wikipedia.org/wiki/HtmlUnit";
 
        try {
            HtmlPage page = webClient.getPage(webPageURL);

            //Get all the headings using its XPath+
            List<HtmlHeading2>  h2 = (List<HtmlHeading2>)(Object) page.getByXPath(xPath);
            
            //print the first heading text content
            System.out.println((h2.get(0)).getTextContent());

        } catch (FailingHttpStatusCodeException | IOException e) {
          
            e.printStackTrace();
            
        }

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

Benefits[edit]

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

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

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

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

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

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

<form action="login" method="post">
<input type="hidden" name="goto" value="news">
<table border="0">
<tbody>
<tr><td>username:</td><td><input type="text" name="acct" size="20" autocorrect="off" spellcheck="false" autocapitalize="off" autofocus="true"></td></tr>
<tr><td>password:</td><td><input type="password" name="pw" size="20"></td></tr></tbody></table><br>
<input type="submit" value="login"></form>

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

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

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

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

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

HtmlPage page = null;

String webPageURl = "https://en.wikipedia.org/wiki/HtmlUnit";

        try {
            // Get the first page

            HtmlPage signUpPage = webClient.getPage(webPageURL);

            // Get the form using its index. 0 returns the first form.
            HtmlForm form = signUpPage.getForms().get(0);

            //Get the Username and Password field using its name
            HtmlTextInput userField = form.getInputByName("acct");
            HtmlInput pwField = form.getInputByName("pw");
            
            //Set the User name and Password in the appropriate fields
            userField.setValueAttribute("draftdemoacct");
            pwField.setValueAttribute("test@12345");

            //Get the submit button using its Value
            HtmlSubmitInput submitButton = form.getInputByValue("login");

            //Click the submit button, and it'll return the target page of the submit button
            page = submitButton.click();


        } catch (FailingHttpStatusCodeException | IOException e) {
            e.printStackTrace();
        }

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

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

System.out.println(page.getElementById("me").getTextContent());

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

draftdemoacct

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

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

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

HtmlPage nextPage = null;

        try {
            List<HtmlAnchor> links = (List<HtmlAnchor>)(Object)page.getByXPath("html/body/center/table/tbody/tr[3]/td/table/tbody/tr[92]/td[2]/a");
            
            HtmlAnchor anchor =  links.get(0);
            
            nextPage = anchor.click();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

На этом этапе у вас должна быть вторая страница в объекте 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;

        List<Object> entries = nextPage.getByXPath("/html/body/center/table/tbody/tr[3]/td/table/tbody/tr[1]/td[1]/span");

        HtmlSpan span = (HtmlSpan) (entries.get(0));

        firstItemId = span.getTextContent();
        
        System.out.println(firstItemId);

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

31.

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

Заключение

 

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

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

More from Bright Data

Datasets Icon
Get immediately structured data
Access reliable public web data for any use case. The datasets can be downloaded or delivered in a variety of formats. Subscribe to get fresh records of your preferred dataset based on a pre-defined schedule.
Web scraper IDE Icon
Build reliable web scrapers. Fast.
Build scrapers in a cloud environment with code templates and functions that speed up the development. This solution is based on Bright Data’s Web Unlocker and proxy infrastructure making it easy to scale and never get blocked.
Web Unlocker Icon
Implement an automated unlocking solution
Boost the unblocking process with fingerprint management, CAPTCHA-solving, and IP rotation. Any scraper, written in any language, can integrate it via a regular proxy interface.

Ready to get started?