...

пятница, 12 июля 2013 г.

Человеческий парсер на Selenium WD


Начало




И вот пришла моя очередь покупать автомобиль. Как это делают ребята с работы я видел. Заходят на сайт и следят за предложениями, ну кто постарше покупает газету и просматривает объявления. Все это однообразно и отвлекаться на сиденье, исследование и нажатие по ссылкам не хотелось. Хотелось просто что бы кто то делал это за меня, таких людей не нашлось. Значит надо было заставить делать все это компьютер.

Постановка задачи




Как я видел решение данной проблемы написать парсер, написать скрипт рассылки. Парсер должен собирать данные объявлений с сайта( сайтом я выбрал «из рук в руки»), а рассылка должна отправлять мне на e-mail сообщения о новом лоте. Текст сообщения должен был содержать:


  • ссылку на объявление

  • короткий текст объявления

  • цена автомобиля

  • место продажи автомобиля


Парсер должен отрабатывать каждые N-минут. А после его отработки должны приходить сообщения. Результаты парсинга записываются в базу, а после отправки сообщения на почту, помечать каждое объявления как отправленное. Не хочу же я одно и тоже тысячу раз видеть.

Парсер




Это был самый трудный шаг. Помнится мне, давным-давно, я писал парсер для одноклассников. На PHP. Сначала мне пришлось разобраться в самой соц. сети и понять каким магическим образом оно работает. Потом надо было запомнить все эти сессии, кукисы и последовательность перехода по ссылкам. А превращение всех этих мыслей в код? О ужас. Как же хотелось что бы все происходило понятно. Как хотелось не задумываться о том, что давным давно умеет делать браузер. Как хотелось, что бы моя любимая Наташа наконец-то поняла и главное увидела результаты работы, а не белый текст на черном фоне командной строки.

Вот поэтому и хотелось просто управлять браузером, что бы было понятно и видно. И тут, на сцену выходит Selenium WebDriver. С помощью которого можно управлять браузером, умея только грамотно выбрать селекторы(css, XPath). Логика работы парсера становится прозрачной. Нажать на кнопку, подождать, ввести данные, нажать на кнопку и все. И никаких кукисов. Ура! И главное я буду видеть все живьем, а не в логах.

Подготовительные работы




И так нам надо установить:


  • Java — для запуска Seleniuma.

  • Selenium — собственно сам Selenium.

  • Node.JS — все будет писать на js, поэтому без ноды никак.

  • Mongo DB — база данных.




Далее в папку с проектом надо будет установить несколько модулей для Node


  • wd — для работы с Seleium'ом.

  • async — для уменьшения вложенности нашего кода.

  • mongoose — для работы с базой.

  • swig — для формирования html файлов, которые отправляются на почту

  • emailjs — для отправки сообщений на почту

  • cron — для запуска наших скриптов каждые N-минут(секунд)




Напомню что установка модулей выглядит так:

npm install "имя модуля"




Теперь запустим наш selenium

java -jar "Путь к файлу с selenium'ом"




И сервер базы данных

mongod --dbpath "Путь к месту хранения базы"


Пишем парсер




Источник выбрал как уже сказал — «Из рук в руки». Теперь последовательность действий:

Отчищаем все куки

browser.deleteAllCookies();




Выбираем регион

image

Вот в это поле вводим регион, который нас интересует. Регион как и все другие параметры описываем в объекте, который будет указан ниже. Ввод региона и нажатие можно описать следующим псевдокодом:



//находи инпут для ввода региона
browser.elementByCss(LOCATOR.cssPath)
.then(function(el){
//набираем регион
return el.type(OPTION.region);
})
.then(function(){
//меняем локатор на первый город в списке
LOCATOR.className = '';
LOCATOR.cssPath = '.b-searchRegion > ul:nth-child(1) > li:nth-child(1)';
return browser.elementByXPath('//span[contains(text(), "' + OPTION.region + '")]');
})
.then(function(el){
//нажимаем на найденный элемент
el.click();
});


Дальше выбираем раздел(мне нужен «Легковые автомобили»)


image


Описать можно просто нажатием на ссылку содержащую определенный текст



//ждем несколько секунд
browser.waitForVisibleByPartialLinkText(OPTION.category,OPTION.elWait)
.then(function(){
//возврат элемента содержащего текст
return browser.elementByPartialLinkText(OPTION.category);
})
.then(function(el){
//нажимаем на найденный элемент
el.click();
})


Теперь заключительная часть установки параметров для поиска, это нажатие на кнопку «больше параметров», ввести цену, год выпуска и остальные параметры. Все это можно посмотреть в видео.

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

Собственно, теперь необходимо собрать данные. Нажимаем на кнопку «Показать», и парсим данные. Получение текста выглядит очень просто



//получаем элемент содержащий текст
browser.elementByXPathOrNull(locationXPath)
.then(function(el){
if(el) {
//получаем текст
return el.text();
}
else{
cb('Нет такого элемента - ' + locationXPath);
}
})




Стоп-сигналом для сбора данных служит отсутствие вот такой вот синей стрелочки «вправо» на странице результатов:

image

После сбора данных записываем их базу. И закрываем браузер.

Кстати вот объект который описывает параметры для поиска автомобиля.

OPTION = {
region : 'Нижний Новгород',//регион поиска
category: 'Легковые автомобили',//категория поиска
price : {from : 0 , to : 1800000},//цена
cy : 'RUR',//валюта
releaseYear : {from : 2010, to : 2013},//год выпуска
mileage : {from : 0 , to : 99000 },//пробег
mark : ['BMW','ВАЗ', 'Audi','Hyundai'],//марка автомобиля
model : ['X1', 'X3', 'X5'],//модель автомобиля
carcass : ['седан', 'хэтчбек'],//кузов автомобиля
transmisson : ['автоматическая', 'механическая'],//трансмиссия
motor : ['бензин'],//тип двигателя
gear : ['задний','передний','постоянный полный','подключаемый полный'],//привод
photo : false,//с фото
video : false,//с видео
district : ['Заречный','Нагорный'],//jrheuf
area : ['Автозаводский', 'Канавинский', 'Ленинский'],//районы
metro : { lines : ['Автозаводская', 'Сормовская'], //линии метро
station : ['Горьковская м.', 'Пролетарская м.']//станции метро
},
source : ['любой'],//источник объявлений
submitted : ['вчера и сегодня'],//время подачи объявления
ajaxWaitMilisec : 2000,//время ожидания ajax мл.сек
elWait : 3000//время ожидания элемента мл.сек
},


Работа с базой




Структура базы следующая

MONGODBSCHEMA : {
title : String, //короткое описание объявления
link : {type : String , unique : true},//ссылка на объявление
price : String,//цена автомобиля
location : String,//место продажи автомобиля
phone : String,//номер телефона подавшего объявления*
text : String, //полное описание объявления*
images : Array,//ссылки на машину*
sms : {type : Boolean, default : false }, //отправилась ли мне смс с этим объявлением*
email : {type : Boolean, default : false }//отправилось ли мне сообщение на e-mail с этим объявлением
}




* — помечены поля которые планировались использоваться, но я решил отказаться от них. В дальнейшем могут понадобиться.

Рассылаем оповещения на почту




Это самые простой момент. Используем для этого модуль emailjs. Выбираем все документы из базы у которых поле «email» установлено в «false». Отправляем на на мой почтовый ящик. Изменяем свойство«email» на «true» у отправленных. Открываем приложение телефона которое отображает наши письма и изучаем подходящие.

Выполняем все каждые N-минут




Используем для этого модуль cron. Запускаем каждые 20 минут сначала парсер, а затем рассылку писем.

Вот и все




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

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

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends: 'You Say What You Like, Because They Like What You Say' - http://www.medialens.org/index.php/alerts/alert-archive/alerts-2013/731-you-say-what-you-like-because-they-like-what-you-say.html


Комментариев нет:

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