xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Модуль Parser — парсинг сайтов

Описание

Модуль Parser предназначен для парсинга любых html страниц в сущности (ноды, термины, юзеры и т.д.). Собственно на этом описание модуля можно закончить =)

Парсинг

Принцип работы парсера похож на работу поисковиков — он загружает одну из страниц сайта, ищет на ней ссылки и начинает ходить по ним в глубь. Встретив страницу, которая попадает под условие "распарсить эту страницу", модуль создает объект сущности и начинает выполнять пользовательский php код, заполняя поля и свойства. Картинки выкачиваются на сервер, создаются отсутствующие термины, значения приводятся к нужному типу.

Использование

Сразу хочу предупредить, что без знаний php работать с модулем будет крайне затруднительно.

Задания парсера находятся по адресу admin/structure/parser_jobs. По умолчанию там есть только одно — Парсинг шаблонов с drupal.org, которое можно использовать как мануал.

Как начать парсить сайт:

  1. Создаём задание admin/structure/parser_jobs/add.
  2. В поле Стартовый URL указываем начальный адрес. С него парсер начнёт работу.
  3. В поле URL тестовой страницы указываем адрес любой страницы, которая в будущем будет распарсена в ноду. HTML код этой страницы будет использован в качестве полигона.
  4. В поле Глубина указываем глубину, до которой парсер будет шагать по найденным ссылкам (простыми словами, глубина — это количество кликов, которые надо сделать относительно страницы указанной в Стартовый URL, чтобы добраться до страницы с контентом).
  5. Заполняем белый и чёрный список адресов.
  6. В поле Код проверки для дальнейшего парсинга страницы пишем код, который должен вернуть TRUE, если текущая страница попадает под условие "распарсить страницу в ноду".
  7. Указываем тип сущности, которая будут создаваться модулем.
  8. Для каждого поля пишем php код, возвращающий значение поля. В коде можно использовать весь функционал библиотеки phpQuery, парсинг с которой превращается в удовольствие :) С помощью кнопок "проверить" смотрим результат работы кода.
  9. Делаем полный бэкап базы и файлов! При неправильной конфигурации модуль может насоздавать много лишних нод.
  10. Начинаем парсинг.

Модуль запоминает адреса и идентификаторы нод, созданные из этих адресов. При повторном парсинге, модуль лишь обновляет уже существующие ноды.

Скриншот 1
Скриншот 2
Скриншот 3

Скачать модуль
Пример парсинга сайта drupalsn.ru

Написанное актуально для Parser 7.x-2.x
Похожие записи

Комментарии RSS

Норм... затестим))) Но это больше модуль для ленивых

Спасибо за статью.
Нет ли желания переделать и под шестерку тоже? Так то пока еще очень надо.
Спасибо

Спасибо, распробовал. Самому нравится phpQuery

feeds + xpath | querypath
реалізовує це набагато краще, як на мене + гнучкість з обробкою по ходу і впихуванням куди завгодно

к "feeds + xpath | querypath" как понимаю ещё нужен Feeds Crawler? если да, то под семёрку он не работает

Не понимаю как он устанавливается. Пишет в списке модулей "Зависит от Entity (не найден)". Не подскажете в чем может быть причина? Модуль интересно попробывать )

очень круто

Огромное человеческое спасибо за модуль! :)
На дня два облегчил работу по переносу контента из одного старого проекта в новый ;)

СПА-СИ-БО!

а можно сделать так что бы задание парсилось по крону,
тойсть что бы не зависело от интернета того человека кто запускает парсинг

к примеру, я оставил на ночь компьютер парсить (потом через час инет оборвался и заново подключился но парсинг уже остановился

тогда может возможно реализовать (паузу старт ) парсинга

К примеру парсит оно 10 000 страниц (интернет оборвался на 3 000 , что бы можно было нажать продолжить и что бы оно дальше парсило ,а не с начала)

реально такое?

F5

У меня такой вопрос,как сделать так что бы парсер не парсил новые статьи,а только обновил существующие.

(первый раз парсилось 3 000 страниц ,потом 10 000 и вышло так (что первые 3000 большинство не обновилось-я создал новые поля и оно туда ничего не загнало из етой старой 3 000 постов)

можно как то решить это?

Модуль запоминает адреса и идентификаторы нод, которые были созданы из этих адресов. При повторном парсинге, модуль лишь обновляет уже существующие ноды.

> парсинг довольно длительная операция и в один запуск крона она никак не уложится

У меня парсится всего 60 страниц. Может быть они уложатся в запуск одного крона? Как это можно проверить?

я не нашёл красивой возможности запустить batch api в кроне, а писать две реализации пока нет желания

а реально прикрутить гугл транслейт к парсеру?

реально, но я этим заниматься не буду

xandeadx
А почему модуля нет в официальном репозитории?

там жёсткие требования к 3rd library

xandeadx
Это вы про phpquery?
А library api ?
Или лень?

phpquery, codemirror.
library api тут не при чём

Вы извините, что надоедаю, но интересно просто.
А что тогда за требования(думал то, что в составе идти не должны - вот и ляпнул про Library api, что бы сами закачивали)?

всё правильно, все сторонние библиотеки должны ставится самостоятельно. Library api просто детектит их наличие и ничего более.

А как можно сделать так:
Пропарсил сайт, ноды сохранились все в порядки.
Нашел второй сайт, нужно с этого сайта, только в одно поле писать, уже созданных нод.

наверное никак

На странице Оставляется ссылка со спарсенной странице, что: Материал спарсен со страницы:....
Подскажите, зачем там в ссылку вшит anonym.to ? , что бы прямой ссылки на материал не было? И что подставить вместо anonym.to лучше ?

чтобы не светить бэки

А как мне запускать парсинг например по ссылке?

никак

Ну по сути то как то ж наверно можно все таки...типа соединиться по curl и скриптом нажать на кнопку или еще как нить...нет?

нет

А сколько бы стоило внедрить гугл транслейт в парсер?

api уже закрыли

Забыл спросить, а как можно добавить в крон задание ?

Что бы определенное задание работало по крону

День добрый, модуль выше всяких похвал. Один вопрос возник, уж очень быстро есть дисковое пространство, может есть какие то временные файлы или таблицы которые можно почиститить за модулем?

папка parser_cache

/sites/default/files/parser_cache/ ?
Можно без болезнно удалять все?

да

Классный модуль! Чутку его переписал, и отпарсил все шаблоны фритемплейтс ит. Вот http://www.juicestudio.ru/ в разделе шаблоны. Теперь буду пользоваться только им,ибо ранее изобретал велосипеды :). Нужно добавить возможность задержки времени между запросами и подключение через прокси и будет вообще кайф.

задержка появилась в последних коммитах

установил модуль parser 2, все вроде хорошо но вот только как его настроить так чтоб спарсировать вот эту страницу http://www.restoran.ru/msk/catalog/restaurants/all/, помогите пожалуйста уже несколько дней бьюсь, то картинки не отоброжаются, хотя и загружаются на сервер, то одно то другое не получается, замучился, я в php не силен, зарание благодарен!

Здравствуйте xandeadx, спасибо за отличный модуль.

Я ставлю его уже второй раз, до этого устанавливал давно и все отлично работало, но сейчас возникает данная ошибка: "Notice: Undefined index: properties in _parser_get_entity_properties() (line 1642 of E:\Web\sites\all\modules\xandeadx-parser-dfeac08\parser.module)". Я предполагаю, что это связано с новыми версиями PHP, из-за них уже много обсуждений на оф. форуме PHP и Drupal'а. Или, может быть, я что-то не правильно делаю... Подскажите пожалуйста, что это может быть.

@Гость исправил

Спасибо (всего за пять минут!), теперь все работает, но не отображаются никакие поля кроме RemoteID, переустанавливал модуль и проверял в двух браузерах

Извиняюсь, это из-за модуля UUID (хотя странно, что он повлиял).

поставьте dev версию uuid

Спасибо, он мне нужен был чтобы экспортировать контент с одного сайта на другой, но зачем это все, если есть Parser)

Подскажите еще пожалуйста, вот например для поля Image нужно возвращать массив с file и alt, а можно ли как-то расширить это, чтобы указывать еще и $title (в смысле аттрибут img 'title')? В Parser'е искал, не нашел чтобы там alt для изображений где-то был указан. Это не существенно, так как после парсинга наверное это не сложно будет сделать через БД из alt, просто интересно

включите title в настройках поля

В настройках поля Drupal'а включен, при редактировании созданного материала можно указать

Спасибо большое, просто не знал где искать.

И, еще хотел сказать, раз есть такая возможность: если в структуре материалов нету поля body, то при сохранении и/или выполнении тоже возникает ошибка про "Undefined index: body", но стоит добавить поле body и все начинает работать. Сейчас использую парсер с Hidden полем body, после вашего ответа думаю, что это наверное тоже из-за Entity

...И issue там очень похожий на это есть

Да, теперь все работает без body, спасибо

Здравствуйте еще раз, xandeadx

А из-за чего может возникать предупреждение при парсинге: "Strict warning: Only variables should be passed by reference в функции eval() (строка 2 в файле E:\Web\www\sites\all\modules\parser\parser.module(710) : eval()'d code)."?

Существенно ли это? Я парсю изображения с файлового хостинга, и некоторые из них странно выводятся после парсинга: в оригинальном размере отображаются правильно, а в измененных размерах не отображаются (и даже не создаются). Кажется, это предупреждение и проблема с изображениями возникает когда в названии содержится знак процента.

...хотя теперь это наверное уже не актуально, т.к. без прокси они блокируют доступ даже с задержками. Интересно, можно ли PHP-запросы пустить через Tor

А как правильно спарсить форум? Предположим, пользователей можно создать заранее (они, кстати, не парсятся, кажется там недостаточно полей, в частности нет поля пароля), темы форумов парсятся хорошо, а как сделать ответы в теме, чтобы если отвечал один и тот же пользователь — сообщения создавались так же от одного пользователя? Можно, например, при парсинге одной страницы запомнить переменную имени пользователя так, чтобы к ней был доступ при парсинге другой страницы? И как на одной странице с ответами на форуме распарсить каждый ответ в отдельный комментарий? И если мы уже спарсили главное сообщение темы, то для ответов необходимо указывать его по ID, и получается, что если необходимо создавать все комментарии в одной теме, надо знать ее ID, вместо того чтобы просто спарсить и сравнить названия... (это чтобы сразу несколько тем парсить)

Наверное, настолько все автоматизировать невозможно, но знать хотя бы как из одной страницы сделать несколько материалов/комментариев?

чтобы если отвечал один и тот же пользователь — сообщения создавались так же от одного пользователя?

поле author

Можно, например, при парсинге одной страницы запомнить переменную имени пользователя так, чтобы к ней был доступ при парсинге другой страницы?

поле remote id

И как на одной странице с ответами на форуме распарсить каждый ответ в отдельный комментарий?

включите режим списка

Большое спасибо xandeadx

Добрый день.
Первым заданием парсера нужный контент получен. Сейчас появилась задача устанавливать на сайте такие цены, как на источнике.
Попробовал создать новое задание,в дополнитеольных параметрах "Не обновлять сущности" чек бокс не установлен.
В журнале ошибка парсера при сохранении, что логично:
Ошибка при сохранении сущности: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ' 94047' for key 'sku'

Как обновлять/возможно с помощью парсера?

запускайте первое задание

более удобного варианта нет для обновления лишь одного поля?

заполните код только для одного поля

заполните код только для одного поля

справедливо, если изменить задание с помощью которого был спарсен контент, но это задание нужно будет для новых запусков.
А новое задание не обновляет товары, спарсенные другими заданиями, поэтому и спрашивал, как можно сделать не испортив исходное

подскажите,почему после обновления файлов модуля не проходит update.php(с ошибками)
перед обновлением:

ОЖИДАЕТСЯ 9 ОБНОВЛЕНИЙ
parser module
 
7203 - Add new col to {parser_jobs}
7204 - Rename {parser_map}.page_key to {parser_map}.remote_id
7205 - Add new col to {parser_jobs}
7206 - Remove col from {parser_urls}
7207 - Increase size of fields
7208 - Add index in {parser_urls}
7209 - Add new cols to {parser_jobs}
7210 - Remove and add cols in {parser_jobs}
7211 - Add new col to {parser_jobs}

После запуска update.php

http://pastebin.com/7d5qgyGk

и заходе на страницу заданий появляется ошибка
http://pastebin.com/hfx80bJW

переустановите модуль

переустановите модуль

отключить в модулях удалить, и обратно?
пробовал так ...не помогало...ещё раз попробую - о результате отпишусь

прекрасный модуль, а не подскажите, что прописать: в "PHP код для поля The main body text" , чтобы при парсинге удалялись внутренние ссылки на другую страницу внутри текста.

$doc->find('a')->remove();

Спасибо большое!
И еще если Вас не затруднит, последний вопрос =) :
Как очистить Html-код от пробелов,
1. что прописать: в "PHP код для поля The main body text"

2. и что прописать: в Field "field_categories", если нужно материал при парсинге присвоить родительскому термин к примеру taxonomy/term/55

Заранее благодарен, с уважением Олег!

Спасибо! Правда с очисткой пробелов так и не получилось разобраться ну ладно. =) Всплыл, еще один вопрос наверное это относительно - Парсинг списков.
1.Если на странице и внутри текста несколько фотографий, который хотелось бы все спарсить , что прописать в "PHP код для поля Showcase Image" , чтобы добавилось несколько фотографий.
Showcase Image - это галерея фотографий.
Возможно ли это =)?
2. ссылка на спарсиной странице ведущая на оригинал видна только с правами админа. Как это побороть, чтобы видели все пользователи =)
Заранее благодарен. Пока реклам ку на сайте посмотрю ;)

1. если нужно в одно поле записать несколько фото, то режим списка вам не нужен. Смотрите дефолтное задание.
2. добавьте соответствующее поле

дефолтное - знать мне бы еще как это =)
вот по этому скрипту

$images = array();
foreach ($doc->find('img') as $b) {
$images[] = substr(pq($b)->attr('src'), 4);
}
return $images;

показываются все фотки но ничего при парсинге не грузиться

а вот при таком скрипте

return array(
'file' => $doc->find('.pic img:first')->attr('src'),
);

грузится но только одна, самая первая фотка в тексте для парсинга.

как быть =( ?

читать комментарии к полю

Подскажите пожалуйста как правильно спарсить поле даты, сделать его системным

что значит "сделать его системным"?

Имел ввиду парсить не в текстовое поле а в поле дата?

не могу понять нужно ли еще для етого добавлять поле data в тип материала?

спасибо, все облазил, не знаю как мог это упустить)

Здравствуйте, спасибо за отличный модуль. Всю ночь пытаюсь разобраться с обновлением существующих нод...

Я спарсила ноды, сделала им Remote ID. Как в другом задании обновлять уже созданные ноды? Я пока смогла только так (в постобработке):

$wrapperForUpdate = entity_metadata_wrapper('node', parser_get_entity_id_by_remote_id('RID'));
$wrapperForUpdate->title = $entity->title;
$wrapperForUpdate->save();

Но чувствую что это неправильно, в частности потому, что парсер все равно своим entity_wrapper'ом новые ноды создает. Пыталась вставлять ID ноды в $entity, в $entity_wrapper вообще ничего не вставляется... Подскажите, как правильно?

в другом задании никак

Тогда сделаю пока $entity->nid = ИД обновляемой ноды, чтобы новые не создавались... А вообще, если кому это интересно, наверное надо еще проверять, есть ли уже такая нода, а то насоздается...

Доброго вечера господа.
Просьба не ругать а как парсить сайт с такой структурой .

тут пусто

тут контент

Как прописать парсинг span уже стал настройювать .

Каким запросом осуществлять парсинг элементов без атрибутов, например:
Жирным выделено то, что необходимо спарсить, остальное - нет

<p>
Some text <br>
Some text<br>
Some text<br>
</p>

<p>
Some text <br>
Some text to parse <br>
Some text to parse<br>
</p>

В приведенном выше примере <p> 2 абзаца можно так и идентифировать по порядковому номеру, но как парсить строки внутри <p>? А задача еще сложнее - отдельные слова внутри строк. Есть ли в PhpQuery запросы для идентификации номера строки и номера слова? Или просто - как сформировать запрос, чтобы спарсить "text to parse" и "text to parse" из приведенного выше примера?
Сам парсер отличный - огромное спасибо!

регулярные выражения

Не могли бы Вы привести пример для парсинга text to parse из второго <p> посредством регулярных выражений. Спасибо!

не понимаю задачи

Задача такая - еще раз:
Есть страница на чистейшем html - вот ее часть:

<p>
Some text <br>
Some text<br>
Some text<br>
</p>

Some text <br>
Some text to parse <br>
Some text to parse<br>

Из всего текста выделено жирным то, что нужно спарсит, то есть только текст: text to parse.
Вопросы:
1. как это сделать с помощью регулярных выражений - с примером если можно
2. возможно ли идентифицировать номер внутри конкретного , по аналогии с p:last?

В вышеприведенном коменте вторая часть текста тоже между <p></p>

preg_match('#Some (text to parse)<br>#')

То есть return $doc->preg_match('#Some (text to parse)<br>#')?

Глупость написал -  return $doc->preg_match('#Some (text to parse)<br>#')
не пройдет - как на PhpQuery подобное сделать?

http://www.php.net/manual/ru/function.preg-match.php

Да, спасибо:)
Можно ли подобно сделать при помощи PhpQuery?
И можно ли каким-нибудь образом все-таки парсить номера строк или слов?

И все-таки можно ли идентифицировать <br> чем-то вроде br:last - я не нашел как, но возможно решение есть?

$doc->find('br:last');

$doc->find('br:last');

Нет, это выдает некорректный результат.

preg_match('#Some (text to parse)#')
Прошу напишите код этого выражения годный для вставки в парсер, нет ни одного примера как вставлять php код, только DOT примеры.

А также назначение полезных функций - где их применить и как?

Полезные функции:
parser_get_pqelements_values($doc, $selector, $function = 'html', $map = 'trim') - возвращает массив значений элементов.
parser_get_entity_id_by_remote_id($remote_id, $job_id = NULL) - возвращает id созданной сущности по Remote ID.
parser_get_entity_by_conditions($entity_type, array $properties = NULL, array $fields = NULL) - возвращает объект сущности по значениям её свойств и полей.

Спасибо

Напишите хоть как регуляркой спарсить - ведь

preg_match('#<title>(.*?)</title>#is', $text, $m);
echo $m[1];

Отдает пустой результат - что не так?

Разобрался - сам ответил на свои вопросы - $page не использовал.

Модуль замечательный, не нарадуюсь, будет ли версия для drupal 6?

нет

Есть ли возможность сделать паузу между запросами менее 1 секунды, но более 0?
при попытке ввода 0,5 или 0.5 сбрасывает на 0.
Вопрос - скажем, спарсили 30 000 нод. Далее необходимо парсить все новые страницы (которые еще не встречались) по крону каждые 3 минуты по 100 нод. В этом случае парсер будет каждые раз по крону проходить 30 000 нод, смотреть что нет изменений и только потом начинать парсить? Есть ли возможность парсить только новые страницы?

Есть ли возможность сделать паузу между запросами менее 1 секунды, но более 0?

нет

В этом случае парсер будет каждые раз по крону проходить 30 000 нод, смотреть что нет изменений и только потом начинать парсить?

парсинг начинается с момента нажатия на кнопку "Сохранить и начать"

Есть ли возможность парсить только новые страницы?

нет

В этом случае парсер будет каждые раз по крону проходить 30 000 нод, смотреть что нет изменений и только потом начинать парсить?

парсинг начинается с момента нажатия на кнопку "Сохранить и начать"

Разве "Периодичность запуска в фоне" - это не запуск задания парсера по крону?
Поясню вопрос еще раз. Отпарсили 30 000 страниц кнопкой сохранить и начать, затем поставили данное задание выполняться по крону. В определенный момент на целевом сайте увеличилось число страниц до 30 005, после этого момента у нас включился крон. Получается парсер пройдет 30 000 уже отпарсенных страниц и только затем дойдет до новых 5 и обработает их?
И еще вопрос - всегда ли парсер обновляет сущности - даже если на таргетовой странице не было изменений, парсер все-равно обновит сущность?. Соответвенно "Не обновлять сущности" это решает?

Есть ли возможность парсить только новые страницы?
Нет

Хм, чисто теоретически, возможно ли сразу после парсинга страницы занесение ее урла в "Чёрный список адресов"?

Получается парсер пройдет 30 000 уже отпарсенных страниц и только затем дойдет до новых 5 и обработает их?

зависит от того где находятся ссылки на новые страницы, если в начале — то обработает первыми

всегда ли парсер обновляет сущности - даже если на таргетовой странице не было изменений, парсер все-равно обновит сущность?

зависит от состояния опции "Не обновлять сущности"

Хм, чисто теоретически, возможно ли сразу после парсинга страницы занесение ее урла в "Чёрный список адресов"?

нет

Как ускорить работу парсера в случае "внутренней" работы - то есть когда он обходит страницы уже сохраненные на диске - увеличить количество потоков или что-то типа того?
Чтобы в случае моих 30 000 страниц уже сохраненных на диске и в том случае если ссылки на новые 5 страниц находятся в конце парсер пробегал эти 30 000 быстро.

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

никак. предназначение модуля — миграция контента, а не сбор данных. если вам нужно что-то иное — пишите своё решение

Поясните почему нельзя использовать модуль для сбора данных? Какие потенциальные нагрузки он может выдержать в случае грамотно настроенного сервера и отличного оборудования. Не будет ли он "задыхаться" от нескольких миллионов страниц из кэша?
В сравнее Feeds vs xandeadx parser, что предпочтительнее для подобного рода задач?

Архитектура модуля рассчитана на запуск в Batch-е, в этом случае никаких ограничений нет, только ресурсы вашего компьютера. Запуск в кроне добавлен в качестве костыля по многочисленным просьбам пользователей. Про нагрузки понятия не имею, посчитайте сами, сколько нужно памяти и процессорного времени, чтобы создать DOM представление 30000 html страниц.

Feeds так же не предназначен для этого.

Вы недооцениваете потенциал своего модуля, по-моему, он вполне подходит для сбора данных.
Если есть статистика, с какими максимальными объемами данных Вам приходилось работать при помощи этого модуля?
Если интересно, у меня примерно такие результаты:
8400 страниц обработано
2100 скачано
6300 взято из кэша
Это за 21 минуту.

В случае работы таргетингового сайта на том же хосте что и сайт-приёмник как-то можно ускорить работу модуля?

admin/structure/parser_jobs/results/* - думаю, следует сделать постраничный вывод по 100 резалтов на страницу - уже при нескольких тысячах браузер начинает страдать.

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

Парсер периодически прекращает работу. Например, при оставшихся 30 000 в очереди парсер может прервать работу на 3%, а может на 5%.
Это происходит из-за не получения ответа от сервера с которого парсят? Почему парсер прекрабщает работу?

Тип сущности: материал - не появляется поле созданное модулем YouTube Field
можно ли это исправить?

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании