Человеческий парсер на 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, просто узнав локаторы элемента. Весь код тут.
А еще я хочу сказать огромное спасибо своей будущей жене Наташе, за то что она не против всех этих моих сумасшедших идей с домашним программирование, и за то что у нее такой бодрящий и милый смех.

ссылка на оригинал статьи http://habrahabr.ru/post/186496/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *