Извлечение информации веб-страницы на основе шаблона в Java
Прямо сейчас я использую Jsoup для извлечения определенной информации (не весь текст) из некоторых сторонних веб-страниц, я делаю это периодически. Это работает нормально до тех пор, пока HTML-код определенной веб-страницы не изменится, это изменение приведет к изменению существующего Java-кода, это утомительная задача, потому что эти веб-страницы меняются очень часто. Также требуется, чтобы программист исправил код Java. Вот пример HTML-кода моего интереса на веб-странице:
<div>
<p><strong>Score:</strong>2.5/5</p>
<p><strong>Director:</strong> Bryan Singer</p>
</div>
<div>some other info which I dont need</div>
Теперь вот что я хочу сделать, я хочу сохранить эту веб-страницу (файл HTML) локально и создать из нее шаблон, например:
<div>
<p><strong>Score:</strong>{MOVIE_RATING}</p>
<p><strong>Director:</strong>{MOVIE_DIRECTOR}</p>
</div>
<div>some other info which I dont need</div>
Наряду с фактическими URL-адресами веб-страниц эти шаблоны HTML будут входными данными для Java-программы, которая будет определять местоположение этих предопределенных ключевых слов (например, {MOVIE_RATING}, {MOVIE_DIRECTOR}) и извлекать значения из фактических веб-страниц.
Таким образом, мне не нужно было бы изменять программу Java каждый раз, когда веб-страница изменяется, я просто сохраню HTML-код веб-страницы и заменю данные этими ключевыми словами, а остальная программа позаботится об этом. Например, в будущем фактический HTML-код может выглядеть так:
<div>
<div><b>Rating:</b>**1/2</div>
<div><i>Director:</i>Singer, Bryan</div>
</div>
и соответствующий шаблон будет выглядеть так:
<div>
<div><b>Rating:</b>{MOVIE_RATING}</div>
<div><i>Director:</i>{MOVIE_DIRECTOR}</div>
</div>
Кроме того, создание таких шаблонов может быть сделано не программистом, а любым, кто может редактировать файл.
Теперь вопрос заключается в том, как я могу добиться этого на Java, и существует ли какой-либо существующий и лучший подход к этой проблеме?
Примечание: во время поиска в Google я нашел несколько исследовательских работ, но большинство из них требуют предварительных данных обучения, и точность также вызывает беспокойство.
6 ответов
Подход, который вы дали, очень похож на подход Гилберта, за исключением части регулярных выражений. Я не хочу вступать в уродливый мир регулярных выражений, я планирую использовать шаблонный подход для многих других областей, кроме информации о фильмах, например, цен, извлечения характеристик продукта и т. Д.
Шаблон, который вы описываете, на самом деле не является "шаблоном" в обычном смысле этого слова: установленный статический контент, который выгружается в вывод с кучей динамического контента, вставленного в него. Вместо этого это "обратный" шаблон - это шаблон синтаксического анализа, который отбрасывается и отбрасывается, оставляя нужные параметры для поиска.
Поскольку ваши веб-страницы меняются регулярно, вы не хотите жестко кодировать контент для слишком точного анализа, а хотите "увеличить" его основные функции, делая минимум предположений. т.е. вы хотите зафиксировать буквальное соответствие ключевого текста, такого как "Rating:", и обрабатывать чередующуюся разметку, такую как
"<b/>"
гораздо более гибким способом - игнорируя это и позволяя ему изменяться без поломок.Когда вы объединяете (1) и (2), вы можете дать результат любому имени, которое вам нравится, но ЭТО Синтаксический анализ с использованием регулярных выражений. т.е. шаблонный подход - это подход синтаксического анализа с использованием регулярного выражения - они являются одним и тем же. Вопрос в том, какую форму должно принимать регулярное выражение.
3A. Если вы используете Java-кодирование для анализа, тогда очевидный ответ заключается в том, что формат регулярного выражения должен быть
java.util.regex
формат. Все остальное является бременем для разработки, "нестандартным" и его будет сложно поддерживать.3B. Если вы хотите использовать анализатор с поддержкой html, то jsoup - хорошее решение. Проблема в том, что вам нужно больше обработки текста и регулярных выражений и гибкость, чем обеспечивает jsoup. Кажется, что он слишком привязан к определенным тегам и структурам HTML и поэтому разрывается при изменении страниц.
3C. Вы можете использовать гораздо более мощный синтаксический анализатор, управляемый грамматикой, такой как ANTLR - форма, вдохновленная backus-naur-грамматикой, используется для управления синтаксическим анализом, и генератор кода вставляется для обработки проанализированных данных. Здесь, грамматические выражения синтаксического анализа могут быть действительно очень мощными со сложными правилами того, как текст упорядочен на странице и как текстовые поля и значения связаны друг с другом. Мощность выше ваших требований, потому что вы не обрабатываете язык. И нельзя избежать того факта, что вам все еще нужно описать уродливые биты, которые нужно пропустить - такие как теги разметки и т. Д. И борьба с ANTLR впервые требует инвестиций в образование, прежде чем вы окупитесь производительностью.
3D. Есть ли инструмент Java, который просто использует простой подход типа шаблона, чтобы дать простой ответ? Ну, поиск в Google не дает много надежды https://www.google.com/search?q=java%20template%20based%20parser&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla%3Aen-GB%3Aofficial&client=firefox-a. Я полагаю, что любая попытка создать такого зверя выродится либо в обычный синтаксический анализ регулярных выражений, либо в более сложный синтаксический анализ с грамматическим управлением, потому что основные требования к сопоставлению / игнорированию / замене текста приводят решение в этих направлениях. Все остальное было бы слишком просто, чтобы на самом деле работать. Извините за негативное мнение - оно просто отражает проблемное пространство.
Мой голос за (3А) - самое простое, мощное и гибкое решение ваших задач.
Здесь не совсем подход, основанный на шаблонах, но jsoup все еще может быть работоспособным решением, если вы просто экспортируете запросы Selector в файл конфигурации.
Ваш непрограммист даже не должен видеть HTML, просто обновите селекторы в файле конфигурации. Что-то вроде SelectorGadget облегчит выбор того, какой селектор будет фактически использоваться.
Как я могу добиться этого в Java, и есть ли какой-либо существующий и лучший подход к этой проблеме?
Шаблонный подход - это хороший подход. Вы привели все причины, почему в вашем вопросе.
Ваши шаблоны будут состоять только из HTML, который вы хотите обработать, и ничего больше. Вот мой пример, основанный на вашем примере.
<div>
<p><strong>Score:</strong>{MOVIE_RATING}</p>
<p><strong>Director:</strong>{MOVIE_DIRECTOR}</p>
</div>
По сути, вы будете использовать Jsoup для обработки ваших шаблонов. Затем, когда вы используете Jsoup для обработки веб-страниц, вы проверяете все обработанные шаблоны, чтобы увидеть, есть ли совпадение.
При совпадении с шаблоном вы найдете ключевые слова в обработанном шаблоне, а затем найдете соответствующие значения на обработанной веб-странице.
Да, это было бы много кодирования, и сложнее, чем указано в моем описании. Ваш Java-программист должен разбить это описание на более простые и простые задачи, пока он или она не сможет кодировать задачи.
Если веб-страница часто меняется, то вы, возможно, захотите ограничить свой поиск такими полями, как MOVIE_RATING, до наименьшей возможной части страницы и игнорировать все остальное. Есть две возможности: вы можете использовать регулярное выражение для каждого поля или использовать какой-то CSS-селектор. Я думаю, что любой из них будет работать, и любой "шаблон" может состоять из простого списка поисковых выражений, регулярных выражений или CSS, которые вы примените. Просто пролистайте список и извлеките то, что вы можете, и потерпите неудачу, если какое-то определенное поле не найдено, потому что страница изменилась.
Например, регулярное выражение может выглядеть так:
"Score:"(.)*[0-9]\.[0-9]\/[0-9]
(Я не проверял это.)
Или вы можете попробовать другой подход, используя то, что я бы назвал "правилами" вместо шаблонов: для каждой части информации, которая вам нужна на странице, вы можете определить выражение (я) jQuery, которое извлекает текст. Часто, когда изменение страницы невелико, одни и те же хорошо написанные выражения jQuery все равно дают те же результаты.
Затем вы можете использовать Jerry (jQuery в Java) с почти такими же выражениями для извлечения искомого текста. Так что речь идет не только о селекторах, но и о других методах jQuery для обхода / фильтрации дерева DOM.
Например, правило для некоторого текста Director будет (в виде sudo-java-jerry-code):
$.find("div#movie").find("div:nth-child(2)")....text();
В правиле может быть больше (и более сложных) выражений, распределенных по нескольким строкам, например, для перебора некоторых узлов и т. Д.
Если вы OO человек, каждое правило может быть определено в его собственной реализации. Если вы отличный человек, вы можете даже переписать правила, когда это необходимо, без перекомпиляции вашего проекта и все еще в Java. И т.п.
Как видите, основная идея здесь состоит в том, чтобы определить правила, как найти ваш текст; и не соответствовать шаблонам, так как они могут быть хрупкими к незначительным изменениям - представьте, если между двумя элементами div был добавлен пробел:). В этом примере я использовал синтаксис, похожий на jQuery (на самом деле это синтаксис, похожий на Джерри, поскольку мы находимся в Java) для определения правил. Это только потому, что jQuery популярен и прост, а также известен вашему веб-разработчику; в конце вы можете определить свой собственный синтаксис (в зависимости от используемого вами инструмента синтаксического анализа): например, вы можете анализировать HTML-код в дереве DOM, а затем писать правила, используя ваши вспомогательные методы, как перемещать его в интересующее вас место. Джерри также дает вам доступ к нижележащему дереву DOM.
Надеюсь это поможет.
Я использовал следующий подход, чтобы сделать нечто подобное в моем личном проекте, который генерирует RSS-канал отсюда, ведущий сайт по недвижимости в Испании.
С помощью этого инструмента я нашел арендованное место, в котором я сейчас живу;-)
- Получить код HTML со страницы
- Преобразуйте HTML в XHTML. Я использовал эту библиотеку, я думаю, сегодня могут быть лучшие варианты
- Используйте XPath для навигации по XHTML к интересующей вас информации
Конечно, каждый раз, когда они меняют исходную страницу, вам придется менять выражение XPath. Другой подход, который я могу придумать - семантический анализ исходного HTML-кода - далеко выходит за рамки моих скромных навыков;-)