Ищу алгоритм парсинга текста статьи HTML-страницы (без меню, футеров и прочего мусора)

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
Сейчас имею свой парсер на регулярках + HtmlDecode (хотя эту связку лучше на HtmlAgilityPack заменить). Но он просто весь текст вытягивает со страницы. А хотелось бы как-то умно достать только главный блок с телом статьи.

Пока у меня такие варианты:
1. В настройках указал брать только явные предложения (начинающиеся с большой буквы, заканчивающиеся на символы «!.?», удалять слишком короткие предложения. Это помогает отсечь текст из разделов меню, но это метод через попу, так как он удалит и короткие предложения в самой статье, если такие встретятся, а также списки внутри сложно оформленных статьей.
2. Можно идти по методу исключения: удалять из кода блоки <div>, <span> с признаками (class \ ID) слов “footer\menu\comment\@copyright”, но все-равно что-то останется. Ведь можно натренировать парсер на популярных движках (Wordpress, DLE…), но все-равно найдутся самописные сайты, у которых верстка без обозначений структуры пойдет, и их коряво обработает.
3. Или придумывать свой метод, например: берем весь текст страницы, потом (хз каким способом, может кучей условий с подсчетами символов, предожений …) ищем концентрацию длинных предожений. Все что за пределами этой «концентрированной» зоны считаем лишним и удаляем.

Гуглил, но в основном находил старые статьи (пару лет) без ответов:
toster.ru - Как получить содержательную часть страницы?
stackoverflow - Как-распарсить-html-в-net
Может появились какие-то новые решения на C#? Можно отдельной библиотекой. К примеру, есть библиотека https://pypi.python.org/pypi/jusText (нашел тут на форуме), но она под питон, а надо бы что-то под C#, чтобы в зенку встроить.
 
  • Спасибо
Реакции: Sergodjan

Dimionix

Moderator
Регистрация
09.04.2011
Сообщения
3 068
Благодарностей
3 100
Баллы
113
Если бы использовался браузер, то что-то типа такого
C#:
return instance.ActiveTab.MainPageArticle;
 

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
Если бы использовался браузер, то что-то типа такого
C#:
return instance.ActiveTab.MainPageArticle;
Ну мне без браузера надо, иначе скорость упадет в разы. Да и этот метод не идеален, вот что он вернул после открытия этой темы:
Tags:



dll

html

htmlagilitypack

парсер контента

парсинг

парсинг текста










Joined:
May 7, 2015





Messages:
373





Likes Received:
228






















Joined:
Apr 9, 2011





Messages:
2,671





Likes Received:
1,949

















return instance . ActiveTab . MainPageArticle ;
Качественные шаблоны (Web/POST/GET) и C# сниппеты на заказ (в рамках zennolab.com/wiki)
Быстро! Недорого! Обращаться в ЛС

Пользователи просматривающие тему (Пользователей: 3, Гостей: 8-)




orka13 ,





WebBot ,





87v









Style
ZennoLab Style


Language
English (US)







Contact Us

Help
Home
Top
RSS
Как видим, основной контент там - ваша подпись. Ну или это просто очень хитрый метод самопиара :-).
 
  • Спасибо
Реакции: Dimionix

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113
2. Можно идти по методу исключения: удалять из кода блоки <div>, <span> с признаками (class \ ID) слов “footer\menu\comment\@copyright”, но все-равно что-то останется. Ведь можно натренировать парсер на популярных движках (Wordpress, DLE…), но все-равно найдутся самописные сайты, у которых верстка без обозначений структуры пойдет, и их коряво обработает.
Это точно не вариант, т.к. придется составлять огромную базу признаков, а в итоге всё равно что-нибудь пойдет не так :-)

3. Или придумывать свой метод, например: берем весь текст страницы, потом (хз каким способом, может кучей условий с подсчетами символов, предожений …) ищем концентрацию длинных предожений. Все что за пределами этой «концентрированной» зоны считаем лишним и удаляем.
Вот в плане теории - это лучшая идея, но вот каким образом такой хитрый "разбор" тегов делать - совершенно не ясно.

Думаю, по логике всё равно придется пользоваться каким-то либами, которые смогут по тегам разложить код страницы, чтобы по нему можно было ходить как по "дереву". Сразу же наверняка стоит задуматься о том, что после генерации "дерева" - можно будет удалить кучу тегов, которые не могут содержать контент (<head></head>, <script></script> и тд - их не так много, могу помочь с составлением списка тегов под однозначное удаление). Потом нужно действительно как-то "пройтись" по такому дереву и сопоставить где будет находиться наибольшее количество текста внутри тегов, которые граничат друг с другом. Но вот каким образом делать такого рода подсчет - сходу в голову ничего не приходит.

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

PS: бегло посмотрел jusTex - судя по коду он это всё и делает) прям как тут описали мы
 
Последнее редактирование:

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
Ну к примеру, для потомков опишу логику на обычных регулярках, как сейчас шаб у меня работает:

1. Берем содержимое BODY:
Код:
string text = project.Variables["Get_rezult"].Value;
string regex = @"<(BODY|body)[\w\W]*</(BODY|body)>";
var reg = new System.Text.RegularExpressions.Regex(regex, System.Text.RegularExpressions.RegexOptions.None);
if (reg.IsMatch(text))
  return reg.Matches(text)[0];
else
  return "";
2. Делаем с результатом HtmlDecode:
Код:
var url = project.Variables["Get_rezult_2"].Value;
var data = System.Net.WebUtility.HtmlDecode(url);
return data;
3. Удаляем лишние скрипты и теги:
Код:
string Test = project.Variables["Get_rezult_2"].Value;
string regexTest = System.Text.RegularExpressions.Regex.Replace(Test, @"<script[\w\W]*?</script>|<style[\w\W]*?</style>|(https?://[\w.:]+/?(?:[\w/?&=.~;\-+!*_#%])*)|(\<br ?/?\>[^\S \ ]*(\r|\n)[^\S \  ]*)", " ", System.Text.RegularExpressions.RegexOptions.Multiline|System.Text.RegularExpressions.RegexOptions.IgnoreCase );
string regexTest1 = System.Text.RegularExpressions.Regex.Replace(regexTest, @"<[\w\W]*?>", " ", System.Text.RegularExpressions.RegexOptions.Multiline);
string regexTest2 = System.Text.RegularExpressions.Regex.Replace(regexTest1, @"[{}]", "");
4. Чистим регулярками лишние пробельные символы и оставляем только длинные предложения, получаем:
Этот и другие сайты могут отображаться в нём некорректно.
Необходимо обновить браузер или попробовать использовать другой.
А хотелось бы как-то умно достать только главный блок с телом статьи.
Да и этот метод не идеален, вот что он вернул после открытия этой темы.
Недорого! Обращаться в ЛС Пользователи просматривающие тему (Пользователей: 3, Гостей: orka13, WebBot, 87v Style ZennoLab Style Language English (US) Contact Us Help Home Top RSS Нажмите, чтобы раскрыть.
Но вот каким образом делать такого рода подсчет - сходу в голову ничего не приходит.
Задача сложная и интересная, надеюсь, что кто-нибудь предложит свои варианты или ссылки о том, как эту задачу решают какие-то инструменты, а там можно будет смотреть и делать по их аналогии.
PS: бегло посмотрел jusTex - судя по коду он это всё и делает) прям как тут описали мы.
Думаю, по логике всё равно придется пользоваться каким-то либами, которые смогут по тегам разложить код страницы, чтобы по нему можно было ходить как по дереву.
Но вот каким образом делать такого рода подсчет - сходу в голову ничего не приходит.
Задача сложная и интересная, надеюсь, что кто-нибудь предложит свои варианты или ссылки о том, как эту задачу решают какие-то инструменты, а там можно будет смотреть и делать по их аналогии.
 
  • Спасибо
Реакции: izubr, Lord_Alfred и Danny

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
Мне тут в личку посоветовали сервис генерации RSS-фида, берет как раз первый пост, без комментариев. будь то форум, или просто новость. Ну и копать можно в эту сторону, искать такие генераторы с бесплатным API, или которые не загнутся под нагрузкой в многоптоке. Но как то стыдно, ведь это решение для ленивых :-), хотелось бы офлайн вариант.
 
  • Спасибо
Реакции: Lord_Alfred

Dimionix

Moderator
Регистрация
09.04.2011
Сообщения
3 068
Благодарностей
3 100
Баллы
113
Кстати, в iPhone и iPad в стандартном браузере Safari есть кнопка "Вид Reader" - режим для чтения статей, на странице остаются только текст и изображения.
Оттуда бы технологию позаимствовать 8-)
 

zortexx

Client
Регистрация
19.09.2011
Сообщения
2 520
Благодарностей
1 223
Баллы
113
100 лет назад на хабре была статья о логике извлечения текста со страницы. Использовался обратный подход: то есть сначала исключались бесполезные элементы, а потом парсилось то, что осталось. Смысл был в построении структурной модели элементов страницы, где у каждого признака есть свой вес и решение об исключении принимается на основе как минимум двух таких признаков. Хидер, навбар, списки навигации, хлебные крошки, футер: главный признак , помимо тегов - обилие ссылок.
 
  • Спасибо
Реакции: orka13

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113
Ну к примеру, для потомков опишу логику на обычных регулярках, как сейчас шаб у меня работает:
Имхо, регулярками такое делать не очень - они априори будут медленнее и более нагружать систему, чем какая-нибудь либа, которая разбирает html на дерево. Я вот с HtmlAgilityPack не работал - он не это как раз делает?

100 лет назад на хабре была статья о логике извлечения текста со страницы. Использовался обратный подход: то есть сначала исключались бесполезные элементы, а потом парсилось то, что осталось. Смысл был в построении структурной модели элементов страницы, где у каждого признака есть свой вес и решение об исключении принимается на основе как минимум двух таких признаков. Хидер, навбар, списки навигации, хлебные крошки, футер: главный признак , помимо тегов - обилие ссылок.
А есть ссылка на ту статью с хабра? Понятно дело, что таких реализаций много, но вот не все опенсорсят это + не каждая хороша )
 

doc

Client
Регистрация
30.03.2012
Сообщения
8 605
Благодарностей
4 596
Баллы
113

VladZen

Administrator
Команда форума
Регистрация
05.11.2014
Сообщения
22 218
Благодарностей
5 843
Баллы
113
Это точно не вариант, т.к. придется составлять огромную базу признаков, а в итоге всё равно что-нибудь пойдет не так :-)


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

Думаю, по логике всё равно придется пользоваться каким-то либами, которые смогут по тегам разложить код страницы, чтобы по нему можно было ходить как по "дереву". Сразу же наверняка стоит задуматься о том, что после генерации "дерева" - можно будет удалить кучу тегов, которые не могут содержать контент (<head></head>, <script></script> и тд - их не так много, могу помочь с составлением списка тегов под однозначное удаление). Потом нужно действительно как-то "пройтись" по такому дереву и сопоставить где будет находиться наибольшее количество текста внутри тегов, которые граничат друг с другом. Но вот каким образом делать такого рода подсчет - сходу в голову ничего не приходит.

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

PS: бегло посмотрел jusTex - судя по коду он это всё и делает) прям как тут описали мы
jusTex - это сторонний софт?
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
Имхо, регулярками такое делать не очень - они априори будут медленнее и более нагружать систему, чем какая-нибудь либа, которая разбирает html на дерево. Я вот с HtmlAgilityPack не работал - он не это как раз делает?....
Просто я основу этого шаблон делал еще в 2015 году, и тогда еще не знал об HtmlAgilityPack. Сейчас попробовал внедрить его, он удобен для разбора DOM-дерева, часто раньше его использовал (путеводитель для новичков при использовании ZennoPoster+xpath+HtmlAgilityPack+POST\GET). Но даже с конвертацией в текст всей статьи он коряво справился. Вот пример шаблона с HtmlAgilityPack , который в теории должен вытянуть только текст, который отображается в браузере, но в итоге вытянул отрывки jQuery-скрипта еще:
Код:
var html = project.Variables["HTML"].Value; // html код из Get-запроса на http://zennolab.com/discussion/threads/ischu-algoritm-parsinga-teksta-stati-html-stranicy-bez-menju-futerov-i-prochego-musora.44165/
var doc = new HtmlDocument();
doc.LoadHtml(html); // создали объект HtmlDocument и загрузили в него html страницу
var node = doc.DocumentNode.SelectSingleNode("//body"); // взяли нужный узел
var InnerText = node.InnerText.Trim(); // текст узла (но на практике его все еще надо чистить от остатков кода <script> и делать HtmlDecode)
return InnerText;
То есть этот код должен был заменить хотя бы 1-3 шаги из моего предыдущего поста. А на практике получилось что он только шаг №1 заменил нормально.
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113
То есть этот код должен был заменить хотя бы 1-3 шаги из моего предыдущего поста. А на практике получилось что он только шаг №1 заменил нормально.
По логике скорее всего нужно предварительно всё таки чистить html код от лишних тегов, которые не могут содержать текст, а потом не через InnerText получать, а как выше писали - классифицировать теги, обходом по дереву. Думаю, раз там есть nod'ы, то по ним можно как-то итерировать и на основе знаний о том, что текст должен быть определенного минимального объема (можно подсмотреть в том же jusText, там в core.py сверху есть) - присваивать веса, а потом на основе весов брать только ту часть, где внутри больше всего концентрация получается. Скорее всего такая задача даже как-то решается алгоритмически (через графы/деревья), но вот я уже ничего с этой области знаний не помню :(
 

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
Я в целом понимаю, что рекомендуют, но изобретать такое детище на C# опыта не хватит. Да и времени куча надо, чтобы командой тестеров отточить алгоритм до идеала. Все надеялся, что есть в сети готовая библиотека, аналог той питоновой. Но раз готовых решений нет, то сматываю удочки, и перехожу на сервисы.
Ну и надеюсь что в будущем команда администрации подправит работу свойства MainPageArticle , и добавит возможность его использования для get-запросов в безбраузерных шаблонах.
 

AZANIR

Client
Регистрация
09.06.2014
Сообщения
405
Благодарностей
196
Баллы
43
есть такой себе парсер статей , Х-light когда-то его юзал , вполне неплохо контент парсил. может позаимствовать у него методы работы.
 

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
Получилось подключить порт Java>C# boilerpipe (https://github.com/rasmusjp/boilerpipe.net). Подобное обсуждалось на форуме, но линки уже устарели.
Результат конечно не идеален, но для начала сойдет. Правда там требует именно старую версию HtmlAgilityPack.dll за 2014 год.
Выслал заявку на конкурс статей. Надеюсь открытое решение на зенке легче будет до идеала довести.
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113
Получилось подключить порт boilerpipe (обсуждалось на форуме, но линки уже устарели) на C#: https://github.com/rasmusjp/boilerpipe.net
Результат конечно не идеален, но для начала сойдет. Правда там требует именно старую версию HtmlAgilityPack.dll за 2014 год.
Выслал заявку на конкурс статей. Надеюсь открытое решение на зенке легче будет до идеала довести.
Вот это ты молодец! А я тут AngleSharp мучаю тоже для конкурса и как раз набрел на интересные результаты прохода по нодам) Для меня это оказалось небольшим открытием, что там не нужно рекурсивно идти, а есть список нод, сложенных последовательно, соответственно это может упростить задачу из этого топика :-)

PS: делаю не парсер контента) но близкое к этому)
PPS: если интересно будет по нодам - напиши в личку, скину пример, мб тоже пригодится :-)


А вот сейчас понял, что всё таки ошибся судя по всему :-)
 
Последнее редактирование:
  • Спасибо
Реакции: orka13

AZANIR

Client
Регистрация
09.06.2014
Сообщения
405
Благодарностей
196
Баллы
43

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113

AZANIR

Client
Регистрация
09.06.2014
Сообщения
405
Благодарностей
196
Баллы
43
просто счас рассматриваю альтернативу HtmlAgilityPack
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113
Регистрация
10.01.2019
Сообщения
32
Благодарностей
11
Баллы
8
Так и к чему в итоге пришли?
 

udder

Client
Регистрация
28.03.2017
Сообщения
595
Благодарностей
118
Баллы
43
4. Чистим регулярками лишние пробельные символы и оставляем только длинные предложения, получаем:
Пример бы такой регулярки, у меня например есть такой текст с лишними знаками пунктуации
Chlupatá kočička MILF s velkými přírodními kozami v amatérském hardcore na webové kameře... Chlupatá amatérská zrzka v koupelně. ... Zralá brunetka amatérská MILF Eva Jayne dostane její chlupatá kunda bušil. ... Další porno stránky zdarma. Chlupatá kundička MILF s velkými přírodními kozami v amatérském hardcore na webové kameře. 1 rok před 14:47 xTits hairy. Mladá kočka miluje péro. ... Chlupatá amatérská zrzka šuká v koupelně. Před 7 měsíci 06:19 Sexu chlupatá, vana, zrzka. Miláček s kulatým zadečkem Melody Cummings šuká běloch. 3 months ago 15:00 OkXXX hairy. .... Zralá brunetka amatérská MILF Eva Jayne se nechá mlátit do své chlupaté kundy. 3 months ago 06:54 AnyPorn hairy, british. Tahle kočka potřebuje, aby jí někdo vylízal její kudrnatou kundu. ... Další porno stránky zdarma.



Не знаю как чистить?
 

orka13

Client
Регистрация
07.05.2015
Сообщения
2 163
Благодарностей
2 163
Баллы
113
  • Спасибо
Реакции: udder

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)