Drupal → Parser 2

04.04.2012

Допилил до более-менее рабочего состояния вторую версию парсера. Основные отличия:

  • Парсить можно в любые сущности зарегистрированные на сайте — ноды, термины, пользователи, комментарии, товары и т.д.
  • Работа с сущностями ведётся с помощью Entity metadata wrappers.
  • Поддержка всех, доступных для записи, свойств сущности — автор, статус и т.п.
  • Все файлы, скачанные парсером, сохраняются в кэше (public://parser_cache) и при повторном парсинге берутся из него.

Модуль не совместим с первой версией, поэтому перед установкой анинсталим её, удаляем папку с модулем и устанавливаем вторую версию.

Прямая ссылка на скачку последнего снапшота Parser 2.

Если отписываете о найденных багах, то обязательно прикладывайте экспорт задания.

Написанное актуально для
Drupal 7
Похожие записи

Комментарии

И еще вопросик как заполнить Product SCU (Ubercart) при выборе типа материала Товар, поля артикул не вижу?

Гость
25.06.2012, 12:54

при обновлении источника спарсенная статья не обновляется в чем может быть проблема ?
----разобрался после очистки кеша, а как кеш чистится или обновляется после обновления страницы он меняется или как ? как то в ручную не хорошо чистить постоянно

Гость
25.06.2012, 15:10

но без очистки страницы не обновляются как быть ?

очищать кэш любым доступным способом

Гость
01.07.2012, 22:14

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

Александр
01.09.2012, 17:46

Подскажите, а как решить следующую проблему, на сайте-доноре одно из полей подгружается при клике по элементу с другого урл через js, <span class="closed" rel="/url">"Нажмите, чтобы увидеть"</span>, как заставить парсер пройти по /url и выдернуть блок с id="parseinfo"?

получите вручную с помощью _parser_get_page_by_url(url)

Как спарсить ноды вместе с комментариями?
В режиме списка есть пример, который работает по кнопке Проверить и действительно возвращает массив комментариев и импортируемого сайта. Но к создаваемой ноде эти комментарии не привязываются.

вместе никак. парсите сначала ноды, потом комментарии

Александр
22.09.2012, 23:02

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

возвращайте NULL, если не нужно заполнять поле

Такой вопрос. Если свяжется автор материалов и захочет:
1. Чтобы по материалам с его сайта была активная ссылка на источник, видимая для посетителей. Можно ли как-то разом будет такое сделать (только для его материалов, а остальные с других сайтов остались бы нетронутыми)?

2. Удалить все материалы взятые с конкретного сайта, можно ли это будет разом сделать, чтобы не затронуть остальные, спарсенные с других сайтов?

1. создайте новое поле
2. можно удалять все сущности созданные в конкретном задании. это ссылка rolback в списке заданий

Добрый день, подскажите пожалуйста последовательность действий, как правильно с помощью парсера добавить товары с набором полей и материалы отображения товаров со своим набором полей для drupal commerce, чтобы они связались через поле commerce_product_reference нужное с нужным товаром.
Предполагаю, что сначала надо создать задание для создания сущностей товара и установить remote_id для каждого товара и занести поля, относящиеся к сущности товара. А затем, то ли как в комментарии немного выше указано, вызвать из постобработки другое задание, которое создает сущности отображений товара и заносит поля (которое создается заранее), то ли как то иначе, может даже проще надо делать, не пойму.
Каков все-таки порядок действий для парсинга в drupal commerce? Спасибо.

в одном задании создаёте product, в другом product display

в одном задании создаёте product, в другом product display

Это я уже понял, не понятно как связать товар с соответствующим product_display. Насколько я понял, после выполнения первого задания где-то хранятся соответствия remote_id и product_id и во втором задании, создающем отображение товара надо в поле product (типа commerce_product_reference) занести значение, которое находится по remote_id такому же, как у текущего элемента.
Вопрос - как получить эти значения из ранее выполненного задания?

Руслан
19.02.2013, 17:53

Спасибо огромное за парсер. Переношу сайт с вп на drupal. все поля парсятся как надо кроме поля даты. из $doc->find('.updated')->attr('datetime'); получаю строку, которую никак не удается передать. пробовал разные варианты:

2013-01-31 14:18:28 +0400
2013-01-31T14:18:28+04:00
2013-01-31

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

Можно как то прикрутить прокси?

Миша Серяк
03.03.2013, 11:40

есть страницы с урлами вида: 'сайт.рф/news/98127.html' , на многие страницы нет ссылок.
Можно ли каким то образом указать для парсера диапазон страниц для обхода?
Например в поле КОД ПРОВЕРКИ ДЛЯ ДАЛЬНЕЙШЕГО ПАРСИНГА СТРАНИЦЫ :
for ($i=0; $i<=98100; $i++) {
_parser_url_add('http://www.19rus.info/news/'$i'.html');
}
return $doc->find('#full-wrapper .news-content-wrapper')->length() == 1;

в стартовом адресе укажите маску http://www.19rus.info/news/[mask:0,98100].html

Марат
23.05.2013, 14:35

Подскажите, пожалуйста, как правильно возвращать значение для поля с датой в виде timestamp, если на сайте-источнике дата указана в виде d/m/Y ?

Сергей
09.06.2013, 10:20

Здравствуйте. Скажите, а сможет ли Ваш модуль парсить папку и находить в ней файлы *.html, каждый из которых "превращать" в ноды?

Как работать с датой
Вот массив который мне нужно вернуть

array(
  'value' => $value, // Дата начала (date, optional)
  'value2' => $value2, // Дата окончания (date, optional)
)

Но он дата не вставляется
пробовал даже так

return array (
'value' => '2013-10-10 00:00:00',
  'value2' => '2013-10-10 00:00:00',
);

местами менял ничего не выходит

дата должна быть в формате timestamp

Большое спасибо автору модуля за его работу!
Подскажите пожалуйста, пару моментов:
1) При создании сущностей нодов есть поля таксономии с множественным значением и в интерфейсе парсера написано:

PHP код, который должен вернуть массив значений поля (array(значение1, значение2, ...)) (тип: list).

Что имеется ввиду - массив имен терминов или массив tid терминов таксономии (термины уже занесены в базу)?

2) То же самое, но при однозначном поле таксономии. В интерфейсе парсера написано:

PHP код, который должен вернуть значение поля (тип: taxonomy_term).

Что имеется ввиду - имя термина или его tid?

3) И аналогичный вопрос относительно автора ноды. Написано:

PHP код, который должен вернуть значение поля (тип: user).

Что там вносить - имя пользователя или его uid?
Заранее спасибо за ответы!

в терминах можно возвращать как имя термина, так и tid. в пользователе - uid

Спасибо за ответ, однако, я там, где множественные поля решил вставлять массивы с именами терминов, а там где одиночные, вставил tid, так множественные поля заполнились верно, а вот там где tid передавался насоздавалось терминов с названиями типа 161, 206 и т.д. Хотя по номерам я проверил - термины с такими tid на сайте у меня уже были. В чем же дело? Может надо было преобразовать строки типа "161" в int?

И еще вопрос - после неудачного запуска задания, в котором создавались сущности-ноды, были созданы новые ненужные термины, если теперь нажать reroll кнопку парсера для данного задания, то эти ненужные термины не уберутся?

1. нужно возвращать число, а не строку
2. нет

Как можно использовать счётчик?
Нужно в поле вставлять значение счётчика пропарсенных в данном задании сущностей.

Гость
24.09.2013, 15:26

На странице, которую распарсиваю есть вкладки (у вкладок свои урлы)
Урлы вкладок я могу получить через _parser_get_page_by_url().

Вот только пока не понял, а как затем вытащить данные на странице вкладки?
Как сообщить parser что нужно взять распарсенные данные на странице по другому урл.

Получается, что в ноду пишется и собираются данные с разных страниц.

$doc1 = _parser_create_phpquery(_parser_get_page_by_url(урл));
$doc2 = _parser_create_phpquery(_parser_get_page_by_url(урл));
...

У модуля есть пара бага/фитчей, из за которых часто непонятно почему при проверке в задании все работает, а при реальном парсинге появляются ошибки.

1) Если в одном поле что нибудь удалить через $doc->find('div')->remove(), то в следующем поле нельзя будет получить доступа к этим данным при парсинге, хотя при тестировании через "проверить" эти данные можно получить. Т.е. кнопка "проверить" не учитывает код из других полей.

2) В каждом задании лучше называть переменные уникальными именами. Не знаю для всех ли полей, но я скопировал код из одного задания (парсинг нод, получение remote id) в другое задание (парсинг комментариев) в поле node (с дополнениями конечно). В итоге кнопка "проверить" показывала нужный результат, а в реальности remote_id для задания комментариев всегда получалось как из задания с парсингом ноды. Долго не мог понять причину, в итоге переименовал переменные в скопированном коде и все заработало.

Еще проблема:
Если у поля с файлом (в частности с изображением) настроить путь сохранения файла в определенную папку (например в sites/default/all/products) с помощью Filefield path, то при первом проходе парсера все сохраняется правильно, а при втором и последующих проходах (обновление ноды) файлы сохраняются прямиком в sites/default/all. Тоже самое происходит и при переименовании файлов через Filefield path.

При запуске по крону, если забыть указать ограничение по количеству создаваемых сущностей - парсер будет работать вечно. Помогает только перезагрузка сервера)
Может сделать какой-то однозначный стопор? И галочку и статус в списке парсов тоже было бы удобно, мне кажется.

Есть сайт, с которого надо забрать более 3000 страниц. Парсер запускается по крону каждые 5 минут и успевает обработать 950 страниц (с задержкой 2с), а дальше крон перезапускается и парсер начинает все заново, с первой страницы, т.е. новые сущности уже не успевают создаваться.

Можно, конечно, увеличить время между запусками крона, но если подобных сайтов/заданий для парсера будет 5-10, увеличение пауз не решит вопрос.

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

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

Спасибо, попробую так. Для добавления только новых страниц - достаточно поставить галочку "Не обновлять сущности" или нужно еще что-то?

нужно прописать адреса страниц, на которых появляется новый контент

Гость
26.06.2014, 12:06

Добрый день, модуль работает отлично. Только возникла проблема и не могу понять в чем проблема. Вообщем с донора парсим html, но внутри html кода есть div блоки, которые не нужны на выходе. Каким образом можно удалить из html блоки с определенным классом??? jQuery знаю, но remove выдает Fatal Eror....

А как можно поставить/снять флаг у новой сущности?
Программно они ставятся легко, но только при наличии nid, а без него - не получается.
А в парсере последний момент - это ровно перед сохранением, после - нет.
Можно с помощью Rules, но не хотелось бы его ставить только ради этого.

У флагов есть настройка - показывать их в качестве полей при редактировании материалов. Может подобным образом давать возможность установить флаги, которые подходят к этому типу материала?

скорей всего только в своём модуле через хук

Сергей
08.07.2014, 15:41

Уважаемый xandeadx покажите пожалуйста структуру массива термина таскономии с иерархией для парсера.

Как добавлять родительский термин я знаю, а вот как цеплять дочерние? Или это не возможно?

Сергей
08.07.2014, 16:45

А если я буду парсить в сущность термин таксономии? В парсере в настройках полей имеется "Родительские термины (parent)". тип: list, подставляю например "AUDI", в журнале ошибка

Ошибка при записи в $entity_wrapper->parent: Invalid data value given. Be sure it matches the required data type and format.
Value:
AUDI

и родитель не создается

родитель должен уже существовать

Сергей
08.07.2014, 16:52

В том то и дело он существует. Я его ручками добавил ).

В поле "Родительские термины (parent)" пишу

return "AUDI";

Это правильно?

скорей всего нужно возвращать tid термина

если тип list, то логично предположить, что на вход требуется массив

Подскажите, пожалуйста.
Парсим товар с сайта по категориям. Т.е. руками в таксономии указываем например return 5 (tid). Т.е. все товары будут принадлежать термину 5.
Потом парсим товары из другой категории на исходном сайте и у нас указываем return 6 (tid другой категории). И получаем следующее создано 50 сущностей и 30 обновлено.
Заходим в категорию 5 и там вместо начального кол-ва товаров на 30 меньше. Т.е. товары из 5 категории перешли в 6.
Подскажите как можно сохранять принадлежность к терму и при парсинге дописывать значения, а не переписывать их. Т.е. 30 товаров из должны принадлежать и 5 категории и 6.

отметьте опцию "не обновлять сущности"

Вадим
03.09.2014, 14:04

Как можно при php запуске конкретного парсера передать ему массив ссылок страниц для парсинга?

$job = parser_job_load(123);
$job->start_url = implode("\n", array(ссылки));
parser_job_save($job);

Хочу с использованием модуля https://www.drupal.org/project/remote_file_source не скачивать оригиналы фоток к себе, но использовать их для превьюшек и тд. Если в поле картинки указать ссылку на файл, то модуль Parser все равно скачает картинку к себе.
Можно ли это как нибудь избежать?

Гость
09.10.2014, 14:04

Скажите, а как можно в обратную сторону парсить страницы. Чтобы сначала брало старые материалы а потом более новые сверху и так же их выкладывало на сайт.

Тимур
16.12.2014, 18:51

Столкнулся с проблемами, не соображу как поступить:

1. Есть поле image, его спокойно добавляю

'file' => $doc->find('.featured-image-inner img:first')->attr('src'),

НО, в дальнейшем мне надо его убать из body, иначе будет дубль в ноде, в поле image и в теле. Где лучше его убрать? Если пишешь в body remove, то в image уже становится элемент не доступен..

2. Нужно в body менять путь к остальным изображениям (img src), также не пойму в какой стадии писать изменение...

Если пишешь в body remove, то в image уже становится элемент не доступен..

делайте clone

Тимур
16.12.2014, 20:23

Спасибо за подсказку, но где мне делать clone? Если в body, то смысла нет, все равно надо будет убить картинку, если в image то там уже не доступна она....

перед тем, как модифицируете $doc

Тимур
16.12.2014, 20:28

Попробовал так в body

$r = $doc->find('.featured-image-inner img:first');
$c = pq($r)->clone();
$doc->find('.featured-image-inner img:first')->remove();

return array(
  'value' => $doc->find('.entry-content')->html(),
  'format' => 'full_html',
);

в image

return array(
  'file' => pq($с)->attr('src'),
);

Не работает.

из $doc не надо ничего удалять, удаляйте из клонированного объекта.
$doc один на все поля

Тимур
24.12.2014, 13:45

Столкнулся с такой проблемой, переношу контент на сайт, который раньше был обновлен с 6 на 7. Проблема с форматом текста. Т.е. в примере указано:

return array(
  'value' => $img,
  'format' => 'full_html',
);

А у меня машинное имя формата Full HTML не 'full_html' а '2'. Пробовал так:

return array(
  'value' => $img,
  'format' => '2',
);

Получаю в логах:

Ошибка при записи в $entity_wrapper->body->format: Invalid data value given. Be sure it matches the required data type and format.
Value:
2

Пробовал передавать число, без кавычек, тоже самое.
Я правильно хоть делаю, что пытаюсь машинное имя передать?

Я передаю машинное имя и все работает. На 6ке были цифры, да, но текущий сайт сразу с 7ки, возможно поэтому такой проблемы у меня не возникает. А какое значение в базе при нормальном, не программном создании поля? В базе вперемешку цифры и машинные имена?

Тимур
24.12.2014, 14:37

В таблице field_data_body в поле body_format стоят числа. Видно форматы перенеслись с числовыми. В таблице filter_format также в поле format числа. При этом типы полей varchar(255) как и положенно.

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

Тимур
24.12.2014, 16:04

Решил в базе поменять значения, и все стало ок.

UPDATE field_data_body SET body_format = REPLACE( body_format,  '2',  'full_html' )

И еще в таблицах
filter
filter_format

Заменил.

Гость
12.01.2015, 18:05

Намекните, как пройти авторизацию? Например на стандартном SMF форуме?

Гость
13.01.2015, 01:03

Ок, получилось авторизоваться через пост. По крайней мере при тестовом запросе, этот код выводит авторизованную страницу:

$post_data = array('user' => 'ХХХ,'passwrd' => 'ХХХ','hash_passwrd' => '');
$result = _parser_post_request('http://manya.org/index.php?action=login2', $post_data, array('max_redirects' => 10));
print $result;

Но почему-то при парсинге сессия не сохраняется?

Гость
13.01.2015, 01:10

Маленькая помарка, там не print а return. Но это не влияет на результат.

Гость
13.01.2015, 01:25

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

Гость
13.01.2015, 03:41

Разобрался!!! /* танцующий смайлик */

В первый код добавляем:
if (preg_match('#PHPSESSID=(.+?);#', $result->headers['set-cookie'], $matches)) {
variable_set('parser_data_PHPSESSID', $matches[1]);
}

Затем созданный нами токен "parser_data_PHPSESSID" используем в HTTP заголовках к серверу (поле в самом низу).

Сори за флуд, и спасибо за модуль! :)

Канат
13.01.2015, 07:11

Добрый день, на http://habrahabr.ru/post/164707/ был пример парсинга данных json. Никак не получается приобщить к своему примеру. Подскажите пож-ста, что на что нужно заменить в JsonExampleParser.inc если выгрузка у меня такая

{"success": true, "data": {"HKT":{
"0":{"price":35610,"airline":"UN","flight_number":571,}, "1":"price":27119,"airline":"CX","flight_number":204,},
"2":{"price":33242,"airline":"AB","flight_number":8113,}}}}

Гость
17.01.2015, 17:39

Доброго вечера!

Подскажите, как при парсинге файла, задать ему имя и расширение?

array(
  'file' => $file, // Файл изображения. (file, required)
  'alt' => $alt, // Текст атрибута "Alt" (text, optional)
)

Наверное тут "(file, required)", через required как-то можно?

$cache_uri = _parser_download_url_to_cache(url_файла);
$file = _parser_copy_file($cache_uri, '/path/to/file.ext');
return array('file' => $file->fid);
Гость
17.01.2015, 18:48

Вопрос в продолжение темы.

Во время экспериментов, было создано много изображений (без родительстких нод). Если удалить их напрямую с сервера, то в дальнейшем получу кучу ошибок при загрузке файлов.

Вопрос как правильно удаляются подобные файлы??
Уже не в первый раз с этим сталкиваюсь..

Гость
17.01.2015, 21:28
$cache_uri = _parser_download_url_to_cache(url_файла);
$file = _parser_copy_file($cache_uri, '/path/to/file.ext');
return array('file' => $file->fid);

Радость была не долгой :(
Данный метод имеет один существенный недостаток.
Парсинг с помощью "_parser_download_url_to_cache" происходит без учета кода предварительной инициализации (авторизации)!

В первый раз сработало потому что авторизованные страницы уже были в кеше, т.к. ранее файл запрашивался стандартным методом:

array(
  'file' => $file, // Файл изображения. (file, required)
  'alt' => $alt, // Текст атрибута "Alt" (text, optional)
)
Гость
18.01.2015, 21:39

Понял, правильно так:
$cache_uri = _parser_download_url_to_cache(url_картинки, $job->headers, FALSE);

Андрей
19.01.2015, 10:42

Привет, помогите советом, парсер работает хорошо, уже пол года пользуюсь, огромное спасибо автору!!! Столкнулся с проблемой, установил чистую сборку (минимум), подключил все что мне нужно и парсер... все парсилось хорошо, без нариканий, и вдруг парсер стал добавлять ноды с дублями картинок, типа xxx.jpg xxx_0.jpg все настройки пересмотрел, модули включал отключал , переустанавливал, не помогает... самое интересное что при нормальном создании нода все номано. Не подскажите куда копать?

дубли создаются при совпадении имён

Андрей
19.01.2015, 10:59

я понимаю что при совпадении но откуда они берутся, если на фтп нет файлов, кэш чистый... и ещё файл xxx.jpg в текстовом редакторе смотрится как html страница а фаил xxx_0.jpg это исходная картинка

Андрей
19.01.2015, 12:06

вопрос снимается, проблема дублей была из-за повторных ссылок в BODY , теперь другой вопрос: как в BODY указать глобальную переменную типа $_SERVER['HTTP_HOST'] , что бы при переносе с localhost ссылки автоматом становились типа: domain.com

Алексей
22.01.2015, 22:31

При создании нового парсера при нажатии сохранить выдаёт ошибку:
drupal_write_record() (строка 7239 в файле /home/cp475123/public_html/домен.ru/includes/common.inc).

Алексей
22.01.2015, 22:43

Вопрос снимается, решил уменьшением времени автозапуска.

Вадим
30.01.2015, 19:51

Александр, а есть ли возможность выполнить парсинг с получением значения по 1 url.

То есть на куждую ноду созданную, нужно допарсить с другого url ууникального для каждой ноды, то есть как можно для одного филда ноды допарсить с другого url тут же чтобы не создавать доп контент тайп, views, пересохранение ... ? Спасибо Вам

Добавить комментарий