В статье описан один вариант реализации цикдического парсера на python. Что вкладывается в понятие циклический парсер и каковы его особенности, можно прочитать в статье. Если коротко - циклический парсер извлекает данные по фиксированному адресу (с динамической информацией), образаясь к нему циклически (через заданные промежутки времени).
Также помним, что html - подмножество языка xml, значит парсер будет подходить и для html страниц с данными. При написании парсинга использовался скрипт xmlIterParser, прочитать о нем можно в этой статье
Код парсера можно найти на bitbucket
Структура парсера
Важное замечание! Описываемый парсер - это шаблон, некоторая обвязка для создания парсеров различных источников данных (динамических). Источники могут иметь разную xml структуру данных - набор узлов хранящих необходимые данные и пути доступа к этим узлам. Поэтому настройка парсера под конкретный проект предполагает написание некоторого количества кода на python. Тем не менее, парсер разрабатывается с таким учетом, чтобы написание кода было максимально легким. Подробности читаем ниже.
Парсер состоит из python-скриптов
- cycl-parsser.py - скрипт запуска парсера (исполняемый файл)
- daemonize.py - скрипт, содержащий функцию, переводящий работу парсера в фоновый режим
- xmlIterParser.py - скрипт, включает методы класса, выполняющий анализ структуры источника и непосредственное извлечение данных из источника.
- utilFunc.py - скрипт, включающий функции-утилиты
В каталоге _template находятся скрипты-шаблоны для создания проектов парсера для конкретных xml источников
Парсер написан для сохранения извлекаемых данных в бд postgresql.
Как работать с парсером
Парсер - консольное приложение, запускается из командной строки. Краткая справка по параметрам запуска доступна стандартно
./cycl-parser.py -h
Алгоритм применения парсера следуюший
1. Создание проекта
Выполняем команду
./cycl-parser.py -c project_name
В каталоге парсера создается директория project_name в которую копируются файлы настроек проекта.
2. Получем структуру источника данных (опционально)
Данный шаг выполняется, если точно не знаем какие данные и из каких узлов источника будем извлекать.
Чтобы получить структуру источника - нужно указать парсеру его адрес и тип. Эти параметры задаются в project_name/params.py - SOURCEURL, SOURCETYPE.
Запускаем команду
./cycl-parser.py -t [png|svg] project_name
Команда обратится к источнику по адресу SOURCEURL и сохранит в каталоге проекта project_name структуру источника. Формат сохраненения структуры выбирается из допустимых значений png или svg
Сохраненный графический файл помогает понять, какие узлы источника содержат данные, необходимые для извлечения и указать список xpath путей к этим узлам в переменной XPATH2SOURCEDATA
3. Восстанавливаем пути к элементам данных (опционально)
Если структура источника данных незнакома, иерархия структуры, созданная на шаге 2, может не дать полного понимания в каких узлах источника содержится необходимая информация. В данном случае поможет следующий функционал парсера.
Команда восстановления xpath пути к узлу по его характеристикам.
./cycl-parser.py -p 'tagname=title' project_name
Команда по имени тега (узла) вернет массив xpath путей (массив - потому что на разных ветках иерархии могут находиться узлы с одинаковым именем). Путь узлам можно искать не только по его имени, но и по имени атрибута и его значению (если они присутсвуют). Эти три фильтра (имя узла, имя атрибута, значение атрибута) можно комбинировать при вызове команды в любой последовательности. Ни один из фильтров команды не является обязательным. Полный формат вызова команды парсера такой
./cycl-parser.py -p 'tagname=val1, attrname=val2, attrval=val3' project_name
Полученные нужные пути сохраняем в настройках проекта project_name/params.py в переменную XPATH2SOURCEDATA.
Теперь мы можем протестировать какие данные будет извлекать парсер
./cycl-parser.py -x project_name
Команда вернет первые несколько строк, извлеченные из источника данных в формате <имя_узла>:<значение>.
Внимание !!! Нам важно четко понимать, в каком формате парсер будет возвращать извлекаемве данные. Непременное правило - парсер должен возвращать список, каждый элемент которого содержит ровно одну запись. Эти знания необходимы для написания функции насстановки данных (см. ниже шаг 6)
4. Создаем таблицу postgresql
Данный шаг не относится к работе парсера, выполняется вручную. В созданную таблицу парсер будет сохранять извлеченные данные.
Предполагается, что читатель знает как создавать таблицы в postgresql.
5. Настройка параметров проекта
Все параметры проекта хранятся в файле params.py в каталоге проекта. Описание параметров - там же.
6. Написание функции расстановки данных
Это единственный шаг, требующий навыков программирования на python. Он сводится к написанию функции, которая будет расставлять данные каждой извлеченной записи в соответсвии с порядком полей таблицы бд, определенной в параметре настройки FIELDSNAME. Шаблон функции и ее описание хранится в файле parser.py в каталоге проекта. Вот пример функции для проекта, извлекающего данные из стандартной rss ленты новостей
# файл params.py
FIELDSNAME=("link", "title", "description", "pubDate", "category")
# файл parser.py
def parseData(d):
data=['None']*len(FIELDSNAME)
for k,v in d.items():
v=v.replace('\n','')
if k in FIELDSNAME:
data[FIELDSNAME.index(k)]=v
return data
По-моему достаточно просто
7. Запуск парсера на извлечение данных
./cycl-parser.py [-d -i val1 val2] project_name
Параметры, указанные в скобках могут быть опущены (не являются обязательными). Параметр -d запускает парсер в фоновом режиме, параметр -i с обязательным указанием двух целочисленных значений задает периодичность (в сек.), с которой парсер будет обращаться к источнику - val2 и период (в сек.) через который извлеченные данные будут переноситься из csv файла-буфера в таблицу бд. После переноса данных в бд файла-буфер очищается.
Еще один режим работы парсера определяется параметром HASHKEY в файле настроек проекта. По умолчанию значение параметра - пустрой список. Это означает, что сохраняться будут все извлекаемые записи, без проверки их уникальности. Поэтому, если параметром -i задать достаточно короткий период обращения парсера к источнику данных (до того, как данные будут успевать обновиться полностью), то таблица будет содержать записи-дубликаты.
Чтобы избежать этого - необходимо из кортежа полей таблицы (FIELDSNAME) в списке переменной HASHKEY указать одно или несколько полей, которые будут определять уникальность каждой записи. Тоесть, проверка уникальности выполняется не на уровне postgresql, а на уровне парсера.
Принцип работы парсера
В ходе работы парсер выполняет следующие действия
- подключается к указанной базе (единожды, при запуске парсера)
- извлекает данные из источника и сохраняет их в csv файл
- При следующем обращении парсер вновь извлекает данные. Если задана проверка уникальности, то прежде чем добавить очередной объект (запись), парсер проверяет ее на уникальность. Неуникальные записи игнорируются.
- При наступлении времени сохранить извлеченные данные в базу, парсер выполняет эту операцию и затем очищает csv файл.
- цикл повторяется
В ходе работы парсер по заданному в PATH2FILE пути создает следующие файлы
- файл логов - в нем сохраняется время обращения к источнику и количество новых записей, добавленных в csv файл
- сам csv файл
- файл ошибок - хранит время ошибки и ее описание
- файл хешей уникальных записей.