Создание парсера под сайт на основе Express Parse
В основе плагина Express Parse лежит очень гибкий механизм парсинга, не привязанный к программной реализации. Его работа построена на перечне правил поиска текста и цепочек фильтраций, которые находятся в отдельных файлах. Сейчас мы рассмотрим пример, который поможет Вам понять, как можно создать парсер под определенный сайт на основе плагина Express Parse. Однако, для этого Вам необходимо иметь хоть малейшее представление о регулярных выражениях и XPath.
Для начала определимся с сайтом, который мы будем парсить. Я выбрал для примера сайт www.rusarticles.com с бесплатными статьями. Сайт был выбран, так как предоставляет статьи бесплатно, но в любом случае не забывайте об авторских правах и по возможности выставляйте ссылки на источники статей. Обратите внимание, что нужно использовать последние версии BlogBot Ultimate (3.0.5) и Express Parse (1.5).
Шаг первый
Для начала нужно добавить в список сервисов наш сайт. В директории плагина (/plugins/expressparse) есть файл services.txt, в котором храниться список сервисов для парсинга. Открываем этот файл на редактирование обычным текстовым редактором (не нужно использовать MS Word или Writer, рекомендую использовать Notepad++). Добавляем в него строчку такого типа:
rus,RusArticles,http://www.google.com/search?hl=ru&q={QUERY}+site:rusarticles.com&lr=lang_ru
Здесь rus – это идентификатор сервиса (2-4 символа), не должен повторяться, RusArticles – название сервиса (не должен содержать запятых), далее – строка запроса в Google для нашего сайта. Эти три поля должны идти в одну строку и быть разделены запятыми. Если Вы создаете парсер для другого сайта, вам нужно будет не забыть изменить в строке запроса после site: адрес сайта. Для англоязычных сайтов строка запроса может выглядеть так:
http://www.google.com/search?hl=en&q={QUERY}+site:articlesbase.com
Сохранив файл, зайдем в BlogBot на страницу настроек плагина. В списке сервисов появился сайт RusArticles.
Шаг второй
Теперь приступим к написанию правил. Создаем в директории /plugins/expressparse/rules файл с названием домена и расширением txt. У нас это будет .rusarticles.com.txt. Точка впереди означает, что под это правило подходят все сабдомены домена (напр., www.rusarticles.com). Если нужно создать правило для сабдомена, указываем его явно, например, правила sub.domain.ru.txt не будут распространяться на весь домен domain.ru, а только на сабдомен sub.domain.ru. Открываем сайт, который мы будем парсить и переходим на первую попавшуюся статью. Видим что ссылки на статьи имеют вид:
/category_alias/article_alias-article_id.html
В созданном файле пишем следующее:
LocationMatch /-\\d+\\.html$/
Это означает, что правила следующие ниже, будут применены к страницам, адрес которых заканчивается несколькими цифрами, после которых следует .html. В общем случае можно написать так:
LocationMatch /./
Под это условие подходят все страницы. Как Вы, наверное, заметили здесь использованы регулярные выражения. Символ «$» означает конец строки, «\d+» — одна и более цифра, символ «\» идёт дважды подряд, т. к. первый слэш экранирует второй. В правилах следует всегда экранировать слэши и пробелы. Еще пара примеров:
LocationMatch /page=\\d+/
Это условие подразумевает страницы сайта без ЧПУ, когда ID статей указаны в числовом виде.
LocationMatch /\\/category\\/video\\//
Это условие подразумевает статьи из категории video. Директив LocationMatch может быть сколько угодно в пределах файла, и её условие распространяется на все директивы после неё и до конца файла или до следующего LocationMatch. Файл правил всегда должен начинаться с этой директивы.
Далее нам нужно определить, что мы будем “грабить” со страницы. Открываем исходный код страницы, либо пользуемся расширением FireBug для Firefox для просмотра дерева элементов. Видим, что статья заключена в тэг div с атрибутом . Благодаря этому мы можем выбрать часть HTML со страницы с помощью XPath. Для этого используем директиву Filter. Для начала преобразуем текст в объект DOM.
Filter TextToDOM @body
Здесь мы указываем имя фильтра и к чему он будет примерен. Изначально исходный текст страницы храниться в переменной @body. После применения фильтра будет создана переменная dom, в которой и будет находиться наш DOM-объект. Из этого объекта выбираем часть:
Filter SearchDOM dom WithParams path=//div[attribute::class="article_cnt\ KonaBody"] name=body html=true
Здесь после ключевого слова WithParams идет список параметров фильтра. Параметры разделены пробелами. Если в значении параметра будет пробел или символ «\», они экранируются символом «\». Переносов на новую строку быть не должно. Это касается всех директив. В параметре path мы передаем выражение XPath, в параметре name – имя переменной, в которую будет помещен результат, html=true означает, что нам нужно сохранить верстку. Можно также использовать фильтр Search, который использует регулярные выражения. Анализируя исходный код страницы, мы видим, что нужная нам часть находится между тэгами и, поэтому, убедившись, что эти тэги более не встречаются, пишем:
Filter Search @body WithParams pattern=#<index>(.*)</index>#Uis name=body index=1 all=false
Здесь параметр name снова означает имя переменной для результата, index указывает какое из совпадений следует выбрать 0 – всё, 1 – то, что подходит под выражение заключенное в первые скобки и т. д. Параметр all задает тип поиска true – искать все вхождения, false – только первое.
Теперь у нас есть кусок текста с нашей статьей. Однако, в ней могут встретиться левые ссылки или скрипты, мы можем вырезать это безобразие. Для этого мы используем фильтр Replace, указывая, что ищем с помощью регулярного выражения, заданного параметром search. Замена передается в параметере replace, который по умолчанию равен пустой строке, и поэтому мы его не указываем.
Filter Replace body WithParams regexp=true search=#<script.*</script>#Uis Filter Replace body WithParams regexp=true search=#<a.*>#Uis Filter Replace body WithParams regexp=false search=</a>
Готово! Еще нам нужен заголовок. Без него статья не будет добавлена. Разработчики сайта не стали добавлять в заголовок страницы ничего, кроме названия статьи, поэтому название можно взять оттуда. Снова используем фильтр Search:
Filter Search body WithParams pattern=#<title>(.*)</title>#Uis index=1 name=title all=false
Можно также использовать SearchDOM:
Filter SearchDOM dom WithParams path=//title name=title
К сожалению, на сайте RusArticle нет картинок. Но если они там когда-нибудь появятся, их можно будет получить с помощью фильтра DownloadImages, который скачает картинки и заменит пути к ним в тексте. Класс картинкам можно присвоить параметром imgclass.
Filter DownloadImages body WithParams imgclass=alignleft
И финальный аккорд: нам нужно сбалансировать теги (чтобы не было закрывающих без открывающих или наоборот) и удалить всякий мусор из статьи. Для этого у нас есть фильтр WpFormat, который форматирует статью в соответствии с общепринятыми нормами, а также добавляет метку <!–more–>, чтобы выделить превью.
Filter WpFormat body
Правда у последнего фильтра есть один недостаток, он удаляет из текста списки, таблицы и другие подобные элементы, поэтому, если Вы уверены, что в статье нет того, что могло бы исказить её верстку, можно обойтись без него. Данный фильтр полезно опустить, если вы парсите каталоги товаров, анкеты пользователей или другой специфический контент. Соберем все в одну кучу и получим:
LocationMatch /-\\d+\\.html$/ Filter TextToDOM @body Filter SearchDOM dom WithParams path=//div[attribute::class="article_cnt\ KonaBody"] name=body html=true Filter Replace body WithParams regexp=true search=#<script.*</script>#Uis Filter Replace body WithParams regexp=true search=#<a.*>#Uis Filter Replace body WithParams regexp=false search=</a> Filter DownloadImages body WithParams imgclass=alignleft Filter WpFormat body Filter SearchDOM dom WithParams path=//title name=title
Всего 9 строк! Ну разве не прелесть? Теперь было бы неплохо проверить как это будет работать.
Шаг третий
Возвращаемся в BlogBot на страницу плагина, задаем пару ключевиков (пока для теста, дальше – больше). Сохраняем настройки, отметив галочкой только наш сервис RusArticle и опцию «Публиковать в контент BlogBot». Остальные опции отключаем. Переходим на вкладку «Прогресс». Тут у нас должно быть ровно столько ссылок, сколько ключевых слов мы указали. Если их больше, то скорее всего это ссылки, оставшиеся после предыдущих запусков плагина. В таком случае нужно сбросить прогресс. Если у Вас есть еще плагины, кроме ExpressParse, их желательно деактивировать, в свою очередь, ExpressParse должен быть активирован. Открываем в браузере ссылку http://mybb.ru/thread_pl.php?debug_mode&v, где mybb.ru – это домен, на котором находится Ваш BlogBot. На открытой странице должен отобразиться ход работы плагина.
Wed, 02 Jun 10 14:31:21 +0300 : Plugin started: Express Parse Wed, 02 Jun 10 14:31:21 +0300 : Sending request: http://www.google.com/search?hl=ru&q=%D0%BF%D0%BE%D0%BB%D0%B8%D1%82%D0%B8%D0%BA%D0%B0+site:rusarticles.com&lr=lang_ru Wed, 02 Jun 10 14:31:22 +0300 : Connection done Wed, 02 Jun 10 14:31:23 +0300 : Response: HTTP/1.1 200 OK
Возвращаемся к прогрессу и видим новые ссылки. Часть из них – это ссылки на сайт rusarticles.com, остальные должны быть ссылками на Google на следующие страницы поиска. Если там оказались не те ссылки, которые мы ожидали, то, вероятно, Вы сделали что-то не так на первом шаге. Обновляем страницу с ходом выполнения работы. Теперь плагин будет обходить найденные страницы и применять к ним наши правила.
Wed, 02 Jun 10 15:06:40 +0300 : Plugin started: Express Parse Wed, 02 Jun 10 15:06:40 +0300 : Sending request: http://www.rusarticles.com/raznoe-statya/sootnoshenie-prava-i-politiki-513468.html Wed, 02 Jun 10 15:06:45 +0300 : Connection done Wed, 02 Jun 10 15:06:46 +0300 : Response: HTTP/1.1 200 OK Wed, 02 Jun 10 15:06:46 +0300 : Added post: `Соотношение Права И Политики` to category `политика` Wed, 02 Jun 10 15:06:46 +0300 : Can't find rule for http://www.rusarticles.com/privacy-policy Wed, 02 Jun 10 15:06:46 +0300 : Sending request: http://www.rusarticles.com/politika-statya/25-letnij-pacient-umer-v-psixushke-2196867.html Wed, 02 Jun 10 15:06:46 +0300 : Connection done Wed, 02 Jun 10 15:06:47 +0300 : Response: HTTP/1.1 200 OK Wed, 02 Jun 10 15:06:47 +0300 : Added post: `25-Летний Пациент Умер В Психушке` to category `политика`
Судя по этому логу мы видим, что плагин нашел две статьи. Эти статьи теперь находятся в разделе «Контент». Ссылку http://www.rusarticles.com/privacy-policy он не обработал, т. к. она не подошла под условие LocationMatch. Если в результате работы статьи не были найдены, то Вам следует искать ошибки в правилах.
Справка по директивам
Коротко опишу директивы и фильтры, которые можно применять в правилах.
| LocationMatch <ereg> |
| Определяет условие, по которому отрабатывает группа директив, следующая далее. Условие срабатывает, когда адрес страницы подходит под регулярное выражение ereg. |
| Filter <filter_name> <field1> [field2 [...]] [WithParams <key>=<value> [<key>=<value> [...]]] |
| Применяет фильтр filter_name к переменным field1…fieldN с параметрами, указанными после ключевого слова WithParams. В результате работы фильтра может измениться содержимое переменных, либо появиться новые. |
| Skip [NRules] |
| Пропускает NRules директив, по умодчанию NRules равно 1. |
| Condition <field1> [Not] <cond> [N] |
| Пропускает N директив, если переменная field1 не подходит под регулярное выражение cond или если подходит и указано ключевое слово Not. По умолчанию N равно 1. |
Список фильтров, которые можно использовать следующий:
| ArticleAnalyzer | ||
| Фильтр для поиска статьи по умолчанию. Может находить статьи на страницах почти с любой версткой. Однако иногда может выдавать не совсем «чистые» статьи. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| preserveImages | Сохранять картинки или нет. Может быть true или false. | true |
| preserveLinks | Сохранять ссылки или нет. Может быть true или false. | FALSE |
| metaPrefix | Префикс для имен переменных, которые будут содержать мета-данные страницы. | без префикса |
| encoding | Кодировка страницы. | utf-8 |
| resultMinLength | Минимальная длина статьи. Если длина статьи будет меньше этого параметра, статья будет считаться не найденной. | 600 |
| storeMeta | Сохранять мету или нет. Может быть true или false. | true |
| ArticleAnalyzer2 и ArticleAnalyzer3 |
| По функциональной нагрузке и списку параметров аналогичны фильтру ArticleAnalyzer. Различаются лишь результатами работы. Иногда полезно применить последовательно все три фильтра. Если статья не была найдена одним фильтром, то отрабатывает следующий. |
| ConvertEncoding | ||
| Фильтр для преобразования текста из одной кодировки в другую. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| from | Исходная кодировка. Параметр обязателен. | |
| to | Результирующая кодировка. Параметр обязателен. | |
| CyrillicToEntities | ||
| Преобразует кириллические символы в HTML-сущности и наоборот. Могут быть использованы кодировки utf-8, cp1251 и htmlentities. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| from | Исходная кодировка. | utf-8 |
| to | Результирующая кодировка. | htmlentities |
| DownloadImages | ||
| Загружает картинки, найденные в тексте и заменяет пути к ним. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| name | Имя переменной, в которую будут записаны имена загруженных картинок. | image |
| storage | путь к директории, в которой будут сохранены картинки | ./images |
| minwidth | Минимальный размер картинки по ширине, которую можно загружать. | 100 |
| minheight | Минимальный размер картинки по высоте, которую можно загружать. | 100 |
| cut | Если указано true, то картинки, которые не были загружены, будут удалены из текста. | true |
| Remove |
| Удаляет переменные, к которым применён фильтр. Если задан параметр pattern, то будут удалены переменные, подходящие под регулярное выражение, заданное этим параметром. |
| Replace | ||
| Производит замену текста. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| search | Искомая подстрока или регулярное выражение. Параметр обязателен. | |
| replace | Замена. | пустая строка |
| regexp | Определяет является ли параметр search регулярным выражением. | FALSE |
| Rewriter |
| Производит рерайт текста. При использовании фильтра следует учесть, что он весьма ресурсоёмкий. |
| Search | ||
| Производит поиск подстрок в тексте. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| pattern | Регулярное выражение для поиска. Параметр обязателен. | |
| name | Имя переменной, в которую будет записан результат. | data |
| index | Указывает какое из совпадений следует выбрать 0 – то, что подходит под всё выражение, 1 – то, что подходит под выражение заключенное в первые скобки и т. д. | 0 |
| all | Искать все совпадения (true) или только первое (false). | true |
| prefix | Строка, которая будет добавлена к каждому результату слева. | пустая строка |
| postfix | Строка, которая будет добавлена к каждому результату справа. | пустая строка |
| SearchDOM | ||
| Производит поиск в дереве элементов HTML. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| path | Выражение XPath, указывающее на элементы. Параметр обязателен. | |
| name | Имя переменной, в которую будет записан результат. | data |
| prefix | Строка, которая будет добавлена к каждому результату слева. | пустая строка |
| postfix | Строка, которая будет добавлена к каждому результату справа. | пустая строка |
| html | Если равен true, HTML-разметка будет сохранена, иначе результатом будет простой текст. | FALSE |
| Synonym |
| Производит синонимизацию текста. При использовании фильтра следует учесть, что он весьма ресурсоёмкий. |
| TextToDOM | ||
| Создает DOM-объект из HTML-текста. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| encoding | Кодировка текста. | utf-8 |
| useEntities | Конвертировать кириллицу в сущности перед созданием объекта или нет. В некоторых случаях без этой операции кириллица может быть искажена. | true |
| name | Имя переменной для результата. | dom |
| WpFormat | ||
| Форматирует текст, балансируя теги и удаляя мусор. Добавляет метку <!–more–>. После первого абзаца. | ||
| Параметры фильтра | ||
| Название | Описание | По умолчанию |
| thumbMinSize | Минимальный размер превью. Если в первом параграфе будет меньше символов, чем задано параметром, то метка <!–more–> устанавливается после второго или третьего и т.д., пока не наберется достаточное количество текста. | 300 |
| paragrahpMinSize | Минимальный размер параграфа. Если количество символов в параграфе меньше, чем задано параметром, параграф удаляется. | 50 |
Кое-что о переменных
Изначально доступны следующие переменные: @body – HTML страницы, @current-url – текущий URL и переменные с именами, соответствующими именам HTTP-заголовков ответа и начинающихся с символа «%». Одновременно могут существовать несколько переменных с одинаковым именем, в таком случае, фильтр применяется к каждой из них.
Переменные, кроме указания по имени, могут быть указаны с помощю маски:
| Нотация | Значение |
| * | Все переменные. |
| ^pattern | Переменные, начинающиеся на pattern. |
| ?pattern | Переменные, содержащие в имени pattern. |
Заключение
Это все, что я могу рассказать о создании парсеров с помощью ExpressParse. Подробно о регулярных выражениях Вы можете почитать на сайте php.net, а справку по XPath можно получить на сайте w3schools.com. Удачи в начинаниях!
P.S. Если вам никак не удается написать правила для выбранного вами сайта, обратитесь к нам и мы составим его за 5$.
Popularity: 15%



