Здорова господа!
Хочу улучшить свой парсер сайтов, он в общем парсит страницы очень плохо, там после него получается очень много мусора и контент плохо читаемый. Как же все таки писать такой парсер, гугли много, много шарил в интернете, но так ничего и не понял, задавал вопрос на форуме, там мы рассматривали разные вопросы, ну например закон ЦИПФА »
Закон ЦИПФА [tip]Закон Ципфа (Зипфа) — эмпирическая закономерность распределения частоты слов естественного языка: если все слова языка (или просто достаточно длинного текста) упорядочить по убыванию частоты их использования, то частота n-го слова в таком списке окажется приблизительно обратно пропорциональной его порядковому номеру n (так называемому рангу этого слова, см. шкала порядка). Например второе по используемости слово встречается примерно в два раза реже, чем первое, третье — в три раза реже, чем первое, и т. д.[/tip]
Так что такой закон, но это не то, это мне не нужно, пусть поисковики по нему определяют читаемость текста.Он и нужен для определения читаемости текста, мы не будем определять читаемость текста, а будем именно выдирать тот текст из html документа который нам нужен, текст получится сам по себе читаемый, да получается что получится читаемый ну или иначе на сайте не текст, а хз. что изначально не читаемый.
Как же все таки придумать этот универсальный алгоритм? Не знаю честно, мне вообще советовали писать парсер под какой то конкретный шаблон, но мой парсер он сам по себе универсальный и там просто так одним сайтом не обойтись. В принципе если хорошо подумать и посмотреть структуру html документа то можно увидеть что он состоит из блоков, в блоках находится либо текст либо минюшка, либо форма, да что угодно там может находится. Я думаю реализовать свой парсер по следующему алгоритму. Просто проверяем есть ли в тексте тег <h1> или <h2>, если есть выдираем его, дальше разбиваем текст на блоки, я разбивать пока решиль по блочному тегу <p>, возможно это не универсальное средство и да возможно будут сайты на которых текст просто будет оформлен без параграфа, да возмножо текст будет и в блоке <div> но это сайты будут как правило самописные и таких если подумать очень мало, я думаю их меньше одного процента от общего числа сайтов, да и обобщим из этого числа (меньше 1%) будут и норм самописные сайты в который как и положено текст оформляется в теге <p> и поэтому получается что количество «кривых» сайтов еще меньше.
Да основная масса сайтов — проектов в инете как правило сделана на готовых движках ЦМС, а эти движки как правило придерживаются правил оформления текстов и я думаю весть нужный текст будет находится в блоках <p> так что у нас задача сводится к простому — разбить текст на блоки <p>, дальше проанализировать эти блоки, оформить саму статью и проверить отвечает ли требованиям статья, ну требования одни это количество символов в статье, я думаю нужно ставить примерно порог 500 символов, ну хз. 500 возможно будет много и парсер будет медленно работать, ставьте тогда меньше, вообще можете не делать пока такое ограничения, я пока не буду его делать.
Да если разбивка на блоки по тегу <p> это обязательно, то хз стоит ли делать разбивку по списку? Я смотрел сервисы которые выделяют текст из html документа, так они все таки обрабатывают списки и причом еще и добавляют символ табуляции перед строкой которая находится в списке, получается в общем красиво оформлен текст, ну наверно все таки и я добавлю обработку этих тегов, вообще нужно хорошо знать блочные элементы html, html — элементы делятся на блочные и строчные, увы я не силен в списка, да вообще забыл как составляется списки, ну щас посмотрим, разберемся.
Ну от смотрим на код маркированного списка и что мы видим?
1 2 3 4 5 |
<ul> <li>Первый пункт</li> <li>Второй пункт</li> <li>Третий пункт</li> </ul> |
А от список нумерованный.
1 2 3 4 5 |
<ol> <li>Первый пункт</li> <li>Второй пункт</li> <li>Третий пункт</li> </ol> |
А от еще ребятки я увидел что есть еще и «список определений»
1 2 3 4 5 6 |
<dl> <dt>Термин 1</dt> <dd>Определение 1</dd> <dt>Термин 2</dt> <dd>Определение 2</dd> </dl> |
Ну что мы видим из всего этого? Какие можно сделать выводы? Да правильно может ити в абзаце какой то текст — само название списка, а затем уже сам список, от если мы спарсим название списка, но увы мы не парсим сам список, поэтому нам нужно все эти 3 списка парсить, ну и так же само обрабатывать как тег абзаца, потому что в них могут быть так же менюшки и всякая фигня. Получается у нам нужно обязательно разбивать текст html по 4 блочным элементам <p>,<li>,<dt>,<dd>, ну и конечно же каждый блок нужно обрабатывать по своему, от если у нас <li> то перед этой строкой хорошо бы добавить символ табуляции, ну если конечно этот блок пройдет проверку на текст, а перед <dt> нужно так же можно втулить что нит, а уже перед <dd> два символа табуляции, что б оно выделялось хорошо или один символ табуляции перед <dd>, тогда перед <dt> мы ничего не будем добавлять, придумать еще нужно форматирование статьи. Ну что ж пока что все хорошо придумано, можно все это опробовать. Да уже можно писать программу, Для начала мы эти теги выдерем из текста и все их оформим в строку по этому алгоритму: выдираем h1 и разбиваем текст на блоки по <p>,<li>,<dt>,<dd> . Можно приступать, в общем приступаем.
Я буду сюда писать свои мысли по этому поводу, что б хоть как то документировать свои эксперименты, да можно еще посмотреть остальные блочные теги. Давайте их все переберем. Нет не будем разбирает его, он не маленький, да и каждый блочный элемент смысла нету описывать, например ясно что элемент <form> он и нафиг не нужен, там текста нет, так что смысла нету про него что то писать, так же как и про большинство остальных блочных элементов, а от имеет смысл рассмотреть элемент <pre> я его видимо пропусти, все таки нужно посмотреть несколько html документов и проверить что в нем находится.
[tip]
Описание
Элемент <pre> определяет блок предварительно форматированного текста. Такой текст отображается обычно моноширинным шрифтом и со всеми пробелами между словами. По умолчанию, любое количество пробелов идущих в коде подряд, на веб-странице показывается как один. Тег <pre> позволяет обойти эту особенность и отображать текст как требуется разработчику. В отличие от тега <plaintext>, использование которого осуждается в HTML 4, внутри контейнера <pre> допустимо применять любые теги кроме следующих: <big>, <img>, <object>, <small>, <sub> и <sup>.
[/tip]
Да от видите что я интересное нашел, все таки тег <pre> обязательно нужно обрабатывать, в нем не будет картинок, <object>, да и всякой фигни. Там текст будет как правило. Поэтому его также включим в наш список разбивки. Да не зря я все таки решил проверить остальные блочные теги. Их много и из них нужно выбрать те в которых может быть полезный текст. Посмотрим еще дальше что за теги есть. что можно выбрать, но у нас уже 5 тегов есть перечислим их еще раз это <p>,<li>,<dt>,<dd> и <pre> . Эти блоки нужно обязательно обрабатывать. Идем дальше.
Да от все таки меня блок <div> заинтересовал, да он меня в сомнения кидает.
[tip]
Описание
Элемент <div> является блочным элементом и предназначен для выделения фрагмента документа с целью изменения вида содержимого. Как правило, вид блока управляется с помощью стилей. Чтобы не описывать каждый раз стиль внутри тега, можно выделить стиль во внешнюю таблицу стилей, а для тега добавить атрибут class или id с именем селектора.
Как и при использовании других блочных элементов, содержимое тега <div> всегда начинается с новой строки. После него также добавляется перенос строки.
[/tip]
Ну тут видно что он как правило применяется для выделения фрагмента документа с целью изменения вида содержимого. Тут в том то и дело что этим фрагментом может быть как текст, так и какая небуть фигня, да в нем так же могут быть и другие блоки, ну тут сложно что то за него сказать, пока что я явно не могу сказать что его стоит рассматривать, да его в обязательные не будем вносить, его анализ уже добавим когда будет готов основной костяк парсера. Так идем дальше ищем еще что нить хорошее.
И так еще есть теги от <h1> до <h6> они конечно могут попадатся в тексте и просто выделять что нить в тексте, это так называемые заголовки.
[tip]
Описание
HTML предлагает шесть заголовков разного уровня, которые показывают относительную важность секции, расположенной после заголовка. Так, тег <h1> представляет собой наиболее важный заголовок первого уровня, а тег <h6> служит для обозначения заголовка шестого уровня и является наименее значительным. По умолчанию, заголовок первого уровня отображается самым крупным шрифтом жирного начертания, заголовки последующего уровня по размеру меньше. Теги <h1>,…,<h6> относятся к блочным элементам, они всегда начинаются с новой строки, а после них другие элементы отображаются на следующей строке. Кроме того, перед заголовком и после него добавляется пустое пространство.
[/tip]
Видите сами заголовок <h1> он всего один на весь документ. Их таже видимо нужно обрабатывать для улучшения читаемости текста. Вообще нужно видимо как то проверять что находится после тега <h#> если <p> то имеет смысл сохранить этот <h#> Либо какой нить другой тег из перечисленной группы, я думаю этот тег мы включим позднее, хотя смысл имеет его включить, потому что может быть текст отформатирован, да как правило он форматирован и там могут теги <p> быть разделены заголовками, поэтому первое что сразу нужно видимо делать — это проверять тот блок текста который идет за тегом <h#>. Это уже сложнее реализовывать, но нужно полюбом его обрабатывать иначе текст получится не сильно «красывый», хотя может он получится плохим из за обработки этого тега, тут с ним придется повозиться, нужно сделать такую обработку что б мы только получали от нее плюс, что б он не смог ухудшить текст тем что мы его добавили, в общем будем писать такие условия и такую обработку производить, которые в любом случае будут только улучшать качество текста в общем, но никак не ухудшать в частном. Так что так аккуратно сделаем.
Есть еще тег <table> — он рисует таблицу, но мы его не будем смотреть, нам он нафиг пока не нужен, благо таблицы не в каждой статье присутствуют, да я даже не знаю как ее рисовать, хоть я уже почти год с вордпресс. Да в ручную ее можно создать, а в редакторе хз. как это делается. Короче пока что с этим тегом ничего не будем делать. Его улучшение — это уже будет самый пик написания парсера, парсер уже будет примерно 99.9% страниц норм обрабатывать, и 0.01% мы уже улучшим написав или что нить придумав для тега <table>
В принципе мы уже можем приступить к написанию. Просто мы должны выделить блоки и их скинуть в одну строку. Протестим это все на примерно 30 — 40 документах, просто интересно что у нас получиться. Ну что ж приступим.
Ладно господа пока на этом все, я сюда буду писать мысли по дальнейшем построении и улучшении парсера, так что ждите, статья будет развиваться.
Часть два.
Так ребятки здорова, с вами снова я, сделал кое какую обработку, оказывается короче в теге <pre> собран как правило мусор, просто тупо вылазит javascript код, наверно придется все таки убрать обработку тега <pre> потому что ну его нафиг.
Дальше нужно как то эти блоки анализировать. Да сложно их анализировать, честно скажу сложновато. Там много блоков в которых просто всего навсего одна ссылка и все, больше ничего нету, текста в них полезного нету, но что ж делать? Как все таки узнать что находится в блоках? Нам наверняка нужно будет считать количество ссылок в блоке. От я думаю возможно стоит попробовать сделать проверку по следующему алгоритму, ну от щас попробуем придумать вместе с вами. И так мы можем посчитать количество ссылок и количество слов в тексте, правильно? Правильно. От допустим в блоке у нас всего навсего одна ссылка и нет слов, мы ее просто удаляем, дальше нужно уже придумать что делать если в блоке одна ссылка и одно слово, можно его удалить, а можно и оставить, нужно все таки поэкспериментировать и что нить придумать. Ну а если будет 3 слова и больше и одна ссылка, то конечно мы такой текст оставляем, ну это лучше конечно в процентах вычислять, если допустим 50% текста и 50% ссылок, то мы допустим текст оставляем, если все таки меньше 50% текста, то ясно нафиг блок удаляем.
Не знаю что и думать, какой то он такой не сильно прикольный алгоритм, другого правда я пока не вижу, да перед тем еще как считать ссылки и слова, нам походу нужно еще и сам текст обработать — что бы в нем не было лишних тегов. Проводим подсчет соотношения ссылок и текста, ну что ж прошел проверку допустим блок, в нем оказалась все го навсего одна ссылка, отлично, но если ссылок будет много? Что нам тогда делать? Нам нужно проверить их расположение в тексте, относительно текста. Нам нужно будет изъять разделители между ссылками и сравнить их. Вообще возможно несколько ситуаций. От допустим может быть разделитель, а может его и не быть. От если есть разделитель, да он есть, но он вдруг оказался один и тот же разделитель для нескольких ссылок, от палочка вдруг стал разделителем «|» и между всеми ссылками только палочка разделитель, это тоже непорядок, и это скорее всего меню и такие ссылки нужно удалить.
Видите задача усложняется. Дело в том что нужно еще сам порядок определить каждой проверки, от одну проверку прошел делаем вторую проверку, и т.д., этих проверок можно сделать очень много. Я наверно так и поступлю, если не проходит проверку, то просто верну false и все на этом все оборвалось. Как то оно блин все таки и за производительность беспокоишься, хочется что б и скорость работы программы была хорошая.
Да ребятки тут еще придумал я проверку на русский и инглишь текст, можно еще делать проверку на количество русских символов и количество не русских символов, либо вообще символов. В принципе к тексту очень много требований, снова я токо одну теорию делаю, написание проги застопилось. От блин фигово. Нужно все таки как то делать. Но как делать когда нету алгоритма? От я немогу придумать толкового алгоритма, мне придется все тупо экспериментировать. А за изображения мы еще забыли, от как с ними поступать, не с ними ясно их просто нужно будет копировать, старой функцией изображения буду обрабатывать и все, но во время проверок что с ними делать? Видимо как то нужно нам обработать текст, так что б в нем остались только теги <img> и теги <a>, но тут мне в голову приходит такая вещь, что для выделения текста к проверке на ссылки лучше всего одни ссылки оставить и все, те ссылки которые нужно будет удалить, мы их запишем в какой то массив с элементами для удаления из исходного текста ну это понадобится для удаления менюшек, это если текст пройдет проверку на соотношение количества ссылок к количеству слов, ну а ссылки на разделитель проверку не пройдут, нам же ведь нужно будет как то их запомнить, от и введем какой то «массив элементов». Ладно пока попытаемся хоть какую то проверку сделать, а дальше посмотрим.
А да ребятки мы еще не подумали за такую фигню как то что теги могут быть неправильные. Просто блок который мы думаем что он будет включать теги строчные, а он будет оказывается включать блочные теги. потому что где то что то выскочила ошибка, где то неправильный html документ и нам нужно будет видимо проверять на такие теги и сделать наверняка рекурсивный вызов самой главной функции. От видите походу будет такая запутанная функция, что мы фиг что разберем, похоже будет немаленькая функция, короче пока про это не будем думать, короче потом рекурсия нам поможет. Ладно пока что попытаемся хотябы сделать эту задачу, а там посмотрим что получится. И так летсгоу. to be continue…
Часть 3 (день 3 🙂 )Снова привет господа, я снова продолжаю рассуждать на тему создания этого парсера, да очень очень медленно делаю, печально, так же очень печально, я думал все пойдет намного быстрее, но увы… Кароче до сих пор пытаюсь выделить блоки, я даже не перешол к обработке текста, но в принципе в парсере это самое главное выделить блоки, да и алгоритм стал более понятным как что делать, разбиваем на блоки и дальше форматируем текст каждого блока, но тут не все так просто, от я щас на этапе выделения блоков, тут в общем такие дела нужно как то выделять блоки с тегами <h2>….<h6> эти теги как оказалось они очень важны, без них меняется весть смысл текста, это заглавные теги и если мы убираем заглавия то текст меняет сразу же смысл, он не совсем меняет, получается просто сборище разного текста, поэтому очень важно эти теги обрабатывать, от как раз мы в этой части мы и чуток подумаем по поводу их обработки.
От что я надумал, я вообще считаю что в заголовках не должно быть ссылок. Да ребятки нужно видимо делать проверки и от одна из проверок это я считаю проверка на ссылки, от если есть ссылка в заглавии, то это заглавие можно спокойно не добавлять, потому что смысла его нету добавлять, это просто скорее всего будет какая нить менюшка. Так какую еще можно проверку сделать? Вторую проверку которую я решил делать это будет проверка на 😀 … ну в общем я думаю мы должны проверить следующий блок, просто нужно сразу же сделать проверку на блок идущий за <h2>…<h6> от если следующий блок будет «ВАЛИДНЫЙ» блок то мы можем спокойно сохранить в вектор этот блок <h#>, а если он не будет валидным, ну там какая нить фигня идет, ну например идет список ссылок, этот заглавный блок получается заглавие для списка ссылок, ну либо он может так же быть заглавием для какой нить формы или еще что то, то тогда конечно же мы должны его удалить. Эти 2 проверки ИМХО нужно делать.
Я от еще подумываю что же еще можно сделать, какие все таки еще добавить проверки? Эти проверки, что мы добавили они безусловно безопасны, если блок не проходит проверку — он удаляется, а если проходит, то мы его берем и сохраняем и он уж никак не сможет испортить конечный текст, потому что следующий за ним блок «валидный», а это значит, что на 100% это заглавие идет к этому блоку, ну что ребятки видимо достаточно сделать только эти две проверки. Не ну что следующий блок проверять нужно это да, это 100%, а от что в заглавии ссылок не должно быть, ну тут сомнительно, не ну м.б. на каких то сайтах кто то и добавит ссылку в теги <h#> но ИМХО мало вероятно, да я видел эти теги в ссылках <h#> на сайте википедии, но они нам нафиг ненужны, они просто искажают смысла, там просто слова «править» и «изменить». Ну и нашо нам их оставлять? Да ясное дело не нужно, в общем если появляется в теге <h#> ссылка мы этот блок нафиг удаляем, делаем такое обособление — безвредное 🙂 .
Ладно ребятки пожалуй на этом и все, да не так и просто разбить на блоки, да еще хо этот алгоритм явно записать где нить на листочке бумаги или в тетради это что б явно его видеть, я думаю его придется в дальнейшем улучшать и не раз, да полюбом придется улучшать. Так что так, я токо рассуждаю, а нифига не делаю, вроде 5 часов седня его делаю и все на одном месте, делаешь вроде по времени долго, а выхлопа нету, ну ладно в общем ждите продолжения, короче летсгоу 🙂 .
Часть 4.
Здорова! Пытаюсь писать дальше парсер, сегодня начал его тестить и тут облом в общем некоторые страници неправильно парсит, не весть текст, да и некоторые блоки неправильно — это такой как <pre>, а страницы получаются неправильные потому что я не проверяю очень важный блок, а это блок <div>. Короче нужно и этот блок включить.
Я каждый блок проверяю одной функцией, но увы похоже так нельзя делать, нужно каждый блок проверять своей какой нить функцией созданной именно для какого то определенного блока.
Давайте подумаем как же можно проверять блок <div> ведь в нем могут быть различные данные. Тут от сложно что сказать. Тут получается так, что блок <div> может включать в себя все остальные блоки, а может и не включать ни одного другого блока. Как же нам быть? Что же делать? Да можно выборочно выбирать блоки <div> например делать выборку таких блоков <div> у которых внутри не будет тегов <p><pre><h#> и остальных. А можно брать только те блоки <div> в которых не будет других блоков </div> , да нету других блоков <div> но там могут быть <p> <pre> <h#> и что же нам делать ребятки? В принципе можно что то типо рекурсии создать, да рекурсия сразу приходит на ум, да рекурсивный алгоритм, от если мы находим <p></p> мы берем и вызываем функцию для обработки <p>, хотя ребятки смотрите что же получается, мб лучше написать какую нить общую одну функцию которая будет все время сама себя вызывать и находя нужные из <div><p><pre> смотря что находит и опа вылет рекурсии и обработка по новой. Я как то саму суть не могу уловить, только щас ее представляют, да смысл наверно что то писать, нужно видимо пытаться реализовывать, так сказать сам каркас написать именно вызовы.
Да ребятки наверное мы так и сделаем или давайте хотя бы просто попытаемся представить как оно будет работать! Да это будет рекурсивный алгоритм и он в данном случае будет самый правильный да увы мне придется всю прогу переписать, целую кучу условий переписать. Ну да ладно, короче рассуждаем. Что нам нужно сначала сделать? Нам нужно определить один из блоков <p><pre><div><li> находим один из блоков, а дальше? А дальше уже в ход идет наша рекурсивная функция которая принимает текст. И так мы ее вызываем, передаем ей текст и что дальше? А дальше эта функция порциями обрабатывает текст, режет его, пытается найти теги <p><pre><li> находя их вызывает сама себя рекурсивно и… , но вдруг она их не находит, что делать с таким кусочком текста? нам нужно его сохранить в строку. Да ребятки тут самое интересное это то что хз. что может находится в блоке <div>. Там может находится что попало, Там может находится какая нить форма, там может быть меню сайта, да что угодно там может быть. Тут дело в том что в теге <div> может быть просто текст без каких либо тегов, он просто может находится сам по себе, просто без ничего текст также и текст с чем то. Да короче без полнейшей проверки всех тегов, да ребятки скажем прямо всех тегов мы ничего не сможем сделать. Да увы, увы еб та придется все теги что есть проверять, все строчные теги. Сохраню то что у меня щас есть отдельно, моя прога не рекурсивная в принципе работает. Да ребятки еще может быть теги </br> ладно проедим. Ладно пытаюсь писать каркас, а дальше посмотрим что, но рекурсивный способ мне кажется более прикольный.
Парень, изучай другие статьи, книги, смотри, как люди пишут, тебя очень сложно читать. Ты молодец, конечно, пишешь полезные многим новичкам вещи, хорошее дело.
Однако поработай над письмом, перечитывай, что написал, а то иногда даже смешно становится от твоих текстов 🙂 И за грамотностью следи.
Удачи в начинаниях!
Да я вообще стараюсь писать так что б самому потом понятно было.
Вообще пошарив в инете тем по написанию универсального парсера нету, так что я наверно эту тему тоже мб. скоро удалю. Не охота палить тему. Там я конечно мизер написал и много неправильного(код чуток по другому делал) но все рамно много подводящей инфы.