Отладка Java-кода jsoup в продакшене

Отладка 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


<зависимость>


org.jsoup


jsoup


<версия>1.14.3



Эта демонстрация представляет собой тривиальное приложение Java, которое возвращает полный список внешних ссылок и элементов с атрибутами src на странице. Это основано на коде отсюда, преобразованном в Java-программу Spring Boot. Применимый код jsoup относительно короткий:


```java


public Set listLinks (URL-адрес строки, логическое значение includeMedia) выдает IOException {


Документ документа = Jsoup.connect(url).get();


Ссылки на элементы = doc.select("a[href]");


Импорт элементов = doc.select("ссылка[href]");


Результат Set = новый TreeSet<>(String.CASE_INSENSITIVE_ORDER);


если (включить медиа) {


Элементы 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 listLinks(@RequestParam String url, @RequestParam(required = false) Boolean includeMedia) throws IOException {


вернуть 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]»:


image1.png


Это может показать мне методы/строки, которые выполняют этот запрос:


image4.png


Это может сильно помочь в сужении общей проблемной области в иерархии объектов документа.


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


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


```java


"Выполнение запроса {запрос}"


image2.png


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


``` ударить


Запрос ссылок вернул {links.size()}


image5.png


Это создает следующий журнал, который позволяет нам увидеть, что у нас было 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. Преимущество этого заключается в удалении шума от других разработчиков, которые могут работать с журналами. Он также может пропустить проглатывание (опционально).


Чтобы отправлять журналы только в плагин, выберите режим конвейера как «плагин».


image3.png


Сокращение 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)



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE