Отладка Java-кода jsoup в продакшене
21 апреля 2022 г.Парсинг веб-сайтов, созданных для современных браузеров, гораздо сложнее, чем десять лет назад. jsoup — это удобный API, который упрощает просмотр веб-сайтов с помощью обхода DOM, селекторов CSS, методов, подобных JQuery, и многого другого. Но не без оговорки. Каждый парсинг API — это бомба замедленного действия.
Реальный HTML ненадежный. Он изменяется без предварительного уведомления, так как это не документированный API. Когда наша Java-программа терпит неудачу при очистке, мы внезапно застреваем с бомбой замедленного действия. В некоторых случаях это простая проблема, которую мы можем воспроизвести локально и развернуть. Но некоторые тонкие изменения в дереве DOM может быть труднее наблюдать в локальном тестовом примере. В этих случаях нам нужно понять проблему в дереве синтаксического анализа, прежде чем отправлять обновление. В противном случае мы можем получить сломанный продукт в производстве.
Что такое jsoup? HTML-парсер Java
Прежде чем мы углубимся в тонкости отладки jsoup, давайте сначала ответим на поставленный выше вопрос и обсудим основные концепции jsoup.
[Веб-сайт jsoup] (https://jsoup.org/) определяет его как:
jsoup — это библиотека Java для работы с реальным HTML. Он предоставляет очень удобный API для извлечения URL-адресов, извлечения и обработки данных с использованием лучших методов HTML5 DOM и селекторов CSS.
jsoup реализует спецификацию WHATWG HTML5 и анализирует HTML в той же модели DOM, что и современные браузеры.
Имея это в виду, давайте перейдем непосредственно к простому образцу с того же сайта:
```java
Document doc = Jsoup.connect("https://en.wikipedia.org/").get();
журнал (док.название());
Элементы newsHeadlines = doc.select("#mp-itn b a");
for (Заголовок элемента: новостиЗаголовки) {
лог("%s
\t%s",
headline.attr("название"), headline.absUrl("href"));
Этот фрагмент кода извлекает заголовки из Википедии. В приведенном выше коде вы можете увидеть несколько интересных особенностей:
- Подключение к URL-адресу практически бесшовное — просто передайте строковый URL-адрес методу подключения.
- Существуют особые случаи для некоторых дочерних элементов. Например. Заголовок представлен как простой метод, который возвращает строку без выбора из дерева DOM.
- Тем не менее, мы можем выбрать запись, используя довольно сложный синтаксис селектора.
Если вы смотрите на это и думаете: «Это выглядит хрупким». Да, это.
Простой тест jsoup
Чтобы продемонстрировать отладку, я создал простую демонстрацию, которую вы можете скачать здесь.
Вы можете использовать следующую зависимость Maven для установки jsoup в любую программу Java. Maven без проблем загрузит jsoup jar:
```xml
<зависимость>
<версия>1.14.3
Эта демонстрация представляет собой тривиальное приложение Java, которое возвращает полный список внешних ссылок и элементов с атрибутами src на странице. Это основано на коде отсюда, преобразованном в Java-программу Spring Boot. Применимый код jsoup относительно короткий:
```java
public Set
Документ документа = Jsoup.connect(url).get();
Ссылки на элементы = doc.select("a[href]");
Импорт элементов = doc.select("ссылка[href]");
Результат Set
если (включить медиа) {
Элементы media = doc.select("[src]");
for (Источник элемента: медиа) {
result.add(src.absUrl("src"));
//result.add(src.attr("abs:src"));
for (Ссылка на элемент: импорт) {
result.add(link.absUrl("abs:href"));
for (Элемент ссылка : ссылки) {
result.add(link.absUrl("abs:href"));
вернуть результат;
Как видите, мы получаем входной строковый URL-адрес. Мы также можем использовать входные потоки, но это немного усложняет анализ относительных URL-адресов (в любом случае нам нужен базовый URL-адрес). Затем мы ищем ссылки и объекты, которые имеют атрибут src. Затем код добавляет их все в набор, чтобы записи были отсортированы и уникальны.
Мы предоставляем это как веб-службу, используя следующий код:
```java
@RestController
открытый класс ParseLinksWS {
закрытый конечный ParseLinks parseLinks;
общедоступные ParseLinksWS (ParseLinks parseLinks) {
this.parseLinks = разбор ссылок;
@GetMapping("/parseLinks")
public Set
вернуть parseLinks.listLinks (url, includeMedia == null? true: includeMedia);
Как только мы запустим приложение, мы можем использовать его с помощью простой команды curl:
``` ударить
curl -H "Тип контента: application/json" "http://localhost:8080/parseLinks?url=https%3A%2F%2Flightrun.com"
Это распечатает список URL-адресов, на которые ссылается домашняя страница Lightrun.
Отладка сбоев содержимого
Типичные проблемы очистки строк возникают при изменении объекта элемента. Например. Википедия может изменить структуру своих страниц, и описанный выше метод select может внезапно дать сбой. Часто это нюансный сбой, т.е. отсутствует элемент DOM в иерархии объектов Java, что может привести к сбою метода select.
К сожалению, это может быть незаметным сбоем. Особенно при работе с вложенными элементами узлов и зависимостями между документами. Большинство разработчиков решают эту проблему, регистрируя огромное количество данных. Это может быть проблемой по двум основным причинам:
- Огромные журналы — их трудно читать и очень дорого принимать
- Нарушения конфиденциальности/GDPR — очищенный сайт может содержать личную информацию пользователя. Хуже!
- Очищенный сайт может измениться, чтобы включить личную информацию после того, как очистка была первоначально реализована. Регистрация этой личной информации может нарушать различные законы.
Если мы недостаточно регистрируем и не можем воспроизвести проблему локально, все может стать сложнее. Мы застряли в добавлении журналов, сборке, тестировании, развертывании, воспроизведении — цикле повторения промывки.
Lightrun предлагает лучший способ. Просто отследите конкретный сбой непосредственно в рабочей среде, проверьте проблему и создайте исправление, которое будет работать с одним развертыванием.
ПРИМЕЧАНИЕ. В этом руководстве предполагается, что вы установили Lightrun и понимаете его основные принципы. Если нет, пожалуйста, [ознакомьтесь с документацией] (https://docs.lightrun.com/).
Как найти свой путь в DOM браузера
Предполагая, что вы не знаете, где искать, лучше всего начать с jsoup API. Это может привести вас обратно к пользовательскому коду. Круто то, что это работает независимо от вашего кода. Мы можем найти нужную строку/файл для моментального снимка, покопавшись в вызове API.
Я нажал ctrl (на Mac использую Meta-click) вызов метода select здесь:
```java
Ссылки на элементы = doc.select("a[href]");
И это привело меня к классу Element. В нем я ctrl-кликнул по методу Selector «выбрать» и попал в «интересное» место.
Здесь я мог бы поместить условный снимок, чтобы увидеть каждый случай, когда делается запрос «a[href]»:
Это может показать мне методы/строки, которые выполняют этот запрос:
Это может сильно помочь в сужении общей проблемной области в иерархии объектов документа.
Иногда снимка может быть недостаточно. Возможно, нам понадобится журнал. Преимущество логирования в том, что мы можем производить много информации, но только для конкретного случая и по требованию.
Ценность журналов заключается в том, что они могут отслеживать проблему так же, как обход кода. Точка, в которой мы разместили снимок, является проблематичной для логов. Мы знаем отправленный запрос, но у нас еще нет возвращаемого значения. Мы можем легко решить это с помощью журналов. Во-первых, мы добавляем журнал со следующим текстом:
```java
"Выполнение запроса {запрос}"
Затем, чтобы узнать, сколько записей мы вернули, мы просто идем к вызывающей стороне (которую мы знаем благодаря стеку в снапшоте) и добавляем туда следующий лог:
``` ударить
Запрос ссылок вернул {links.size()}
Это создает следующий журнал, который позволяет нам увидеть, что у нас было 147 ссылок a[href]
. Прелесть этого в том, что дополнительные журналы чередуются с уже существующими журналами в контексте:
``` ударить
02 февраля 2022 г., 11:25:27 org.jsoup.select.Selector select
ИНФОРМАЦИЯ: LOGPOINT: выполнение запроса a[href]
02 февраля 2022 г., 11:25:27 com.lightrun.demo.jsoupdemo.service.ParseLinks listLinks
ИНФОРМАЦИЯ: LOGPOINT: запрос ссылок возвращен 147
02 февраля 2022 г., 11:25:27 org.jsoup.select.Selector select
ИНФОРМАЦИЯ: LOGPOINT: ссылка на выполнение запроса [href]
02 февраля 2022 г., 11:25:27 org.jsoup.select.Selector select
ИНФОРМАЦИЯ: LOGPOINT: выполнение запроса [src]
Избегайте проблем с безопасностью и GDPR
Проблемы GDPR и безопасности могут быть проблемой с утечкой информации о пользователях в журналы. Это может стать серьезной проблемой, и Lightrun поможет вам значительно снизить этот риск.
Lightrun предлагает два потенциальных решения, которые можно использовать в тандеме, когда это применимо.
Передача журналов
Большой проблемой GDPR является прием журналов. Если вы регистрируете личные данные пользователя, а затем отправляете их в облако, они остаются там надолго. Его трудно найти постфактум и очень трудно исправить.
Lightrun предоставляет возможность передавать все вводимые журналы Lightrun напрямую в IDE. Преимущество этого заключается в удалении шума от других разработчиков, которые могут работать с журналами. Он также может пропустить проглатывание (опционально).
Чтобы отправлять журналы только в плагин, выберите режим конвейера как «плагин».
Сокращение PII/черные списки
Личная информация (PII) лежит в основе GDPR, а также представляет собой серьезную угрозу безопасности. Разработчик-злоумышленник в вашей организации может использовать Lightrun для кражи информации о пользователях. Черные списки не позволяют разработчикам размещать действия в определенных файлах.
Сокращение PII позволяет нам скрывать из журналов информацию, соответствующую определенным шаблонам (например, формат кредитной карты и т. д.). Это можно определить в веб-интерфейсе Lightrun с помощью роли менеджера.
TL;DR
В парсинге содержимого Java jsoup является очевидным лидером. Разработка с помощью jsoup — это гораздо больше, чем операции со строками или даже обработка аспектов подключения. Помимо получения объекта документа, он также обрабатывает сложные аспекты, необходимые для элемента DOM и сценариев.
Скрапинг — дело рискованное. Он может сломаться в мгновение ока, когда сайт немного изменится.
Хуже того, он может сломаться для некоторых пользователей странными способами, которые невозможно воспроизвести локально.
Благодаря Lightrun мы можем отлаживать такие сбои прямо в рабочей среде и быстро публиковать рабочую версию. Вы можете использовать Lightrun бесплатно, зарегистрировавшись здесь.
Также опубликовано [Здесь] (https://talktotheduck.dev/debugging-jsoup-java-code-in-production-using-lightrun)
Оригинал