Парсер каталогов

20.06.17

Учетные задачи - Оптовая торговля

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

Многие считают, что парсер – нечто сложное и не понятное. Так ли это?

Я не программист, ни по образованию, ни по роду занятий. Но люблю разбираться в разных вопросах. Поэтому решил разобраться и с парсерами. Тем более, что занялся продажей автомобильных масел и фильтров. Рыться в каталогах – долго и муторно. Охота так, чтобы отжал продавец кнопку, а ему показало, что нужно подать покупателю. Поэтому задача запарсить сайт производителя фильтров, записать все в БД, чтобы было доступно локально.

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

Процесс установки и настройки WAMPили LAMPописывать нет смысла.

 И так, приступим. Для начала надо изучить объект. Открываем страницу каталога. Открываем ее исходник. Любой такой каталог начинается с выбора производителя авто. Исходник содержит производителей и их Id в списке <select>. Это и будет нашей первой таблицей в БД. Создаем ее в PHPMyAdmin, обозвав _car_brand.

Первый столбец brand_id (Primary), второй brand_name. Я эту таблицу заполнил, написав разовую программку, которую тут же стер. Она использовала simple_html_dom и брала данные со страницы каталога. Можно заполнить вручную. Цель этой статьи не в том. Мы решаем дальнейшую проблему, уткнувшись в которую, многие не знают, как поступить, и забрасывают свой парсер.

Все дело в том, что страница меняется на экране динамически путем ajax запросов, при этом ее исходный текст остается неизменным. Т.е. куда то летит запрос и возвращается JSON. Потом на клиенте свежие данные обвешиваются HTML тегами. Вот эти запросы мы и будем формировать.

Создаем файлик poisk.php и открываем его в Notepad++. И начинаем кодить:

<?php

// считываем ИД производителя авто

$brandId=$_REQUEST["selBrand"];

// Если еще не выбирали производителя (1й этап)

if ($brandId == 0){

                echo 'ВЫБЕРИТЕ ПРОИЗВОДИТЕЛЯ<form method="POST" action="poisk.php">                                                     <select name="selBrand">';

                $database = 'db_6';

                $link = mysql_pconnect("mysql.ru", "dbu1", "polk");

                mysql_select_db($database) or die("Немогуподключитьсякбазе.");

                mysql_query("set character_set_server='utf8'");

                mysql_query("set names 'utf8'");

// Берем полный список производителей и выводим

                $car_brand = mysql_query("SELECT * FROM _car_brand"); 

// Цикл по строкам. Кому что не ясно, читаем про работу с БД

                while ($brand_id = mysql_fetch_array($car_brand)){

                               $a=$brand_id[0];

                               $b=$brand_id[1];

                               echo '<option value="'.$a.'">'.$b.'</option>';

                }

                echo '</select>                                                                                                                                                                                <input type="submit" id="btnAppSearch" name="btnAppSearch" value="Go"/></form>';

}

Коротко говоря, считали из базы и вывели полный список производителей…

Дальше интересней. Нам нужна вторая таблица в БД `_car_model с моделями авто. В ней поля (`car_model_id`, `car_model_brand_id`, `car_model_name`). Эту таблицу мы будем заполнять не по циклу, а в процессе работы с программой.

// Если производитель уже выбран

else {

// Считываем прилетел ли ИД модели

$selModel=$_REQUEST["selModel"];



                if ($selModel == 0){

// Производитель выбран, но не выбрана модель (2й этап)

                $database = 'db_6';

                $link = mysql_pconnect("mysql.ru", "dbu1", "polk");

                mysql_select_db($database) or die("Немогуподключитьсякбазе.");

                mysql_query("set character_set_server='utf8'");

                mysql_query("setnames 'utf8'");

// Смотрим имя производителя и его ИД

                $car_brand = mysql_query("SELECT * FROM `_car_brand` WHERE `car_brand_id` = '$brandId'");           

                $brand_id = mysql_fetch_array($car_brand);

                $a=$brand_id[0];

                $b=$brand_id[1];

// Выводим имя производителя без возможности его сменить, только через обновление страницы

                echo '<form method="POST" action="poisk.php">ПРОИЗВОДИТЕЛЬ :                                                          <select name="selBrand"><option value="'.$a.'">'.$b.'</option></select>

                <a href="poisk.php">СМЕНИТЬ</a>

                <br>ВЫБЕРИТЕМОДЕЛЬ : ';

                echo '<select name="selModel">';

// Лезем в локальную БД, смотрим, есть ли в ней модели этого производителя

                $car_model = mysql_query("SELECT * FROM `_car_model` WHERE `car_model_brand_id` = '$brandId'");

                $i=0;

// Если в локальной БД есть модели, то выводим их, счетчик их считает...

                while ($model_id = mysql_fetch_array($car_model)){

                                $c=$model_id[0];

                               $d=$model_id[2];

                               echo '<option value="'.$c.'">'.$d.'</option>';

                               $i++;

                }

Тут вроде пока все просто, но, как мы помним, наша таблица с моделями на сей момент пуста… Поэтому и список будет пуст. Придётся лезть за ним на сайт.

// Если счетчик не посчитал, значит локально их нет...

                if ($i<1){

// Лезем тогда на сайт за моделями

Как уже говорил, в исходнике страницы мы ничего не увидим, поэтому запускаем встроенные в браузер средства отладки. Я пользовался оперой. Поэтому правый клик => посмотреть код элемента. Переходим на вкладку Network, где переходим в под-вкладку XHR. Тут то и отображаются «подпольные» сетевые действия, которые нужно внимательно изучить.  Выбираем в списке автомобиль (я выбрал TOYOTA) и кликаем «дальше»… В окне браузера появляется список с моделями, а на нашей вкладке мы видим что добавилась строка get_models/. Выбрав ее, видим много интересного.  Видим адрес, по которому браузер отправлял запрос. Дальше нас интересует информация, которую браузер отправлял на сайт: Request headers. И данные, которые браузер передал: FormData. Snoopy.class - нам в помощь.

                        include ("Snoopy.class.php");

                               $snoopy = new Snoopy;

// Некоторые параметры Снупи знает, их и указываем от реквеста

                               $snoopy->accept = "application/json, text/javascript, */*; q=0.01";

// Некоторые параметры ему не известны, поэтому указываем как RAW

                               $snoopy->rawheaders["Accept-Encoding"] = "gzip, deflate";

                               $snoopy->rawheaders["Accept-Language"] = "ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4";

                               $snoopy->rawheaders["Connection"] = "keep-alive";

                               $snoopy->rawheaders["Content-Type"] = "application/x-www-form-urlencoded";

                               $snoopy->cookies["PHPSESSID"] = '7b60548db34612bc5af6';

                               $snoopy->cookies["ci_session"] = тут очень много всего было…;

                               $snoopy->host = "www.filter.com";

                               $snoopy->rawheaders["Origin"] = "http://www.filter.com";

                               $snoopy->referer = "http://www.filter.com/catalogue";

                               $snoopy->agent = "Mozilla/5.0 (Windows NT 6.1; WOW64)";

                               $snoopy->rawheaders["X-Requested-With"] = "XMLHttpRequest";

// Шапка закончилась, поэтому формируем массив запроса, передаваемый Пост

                               $submit_vars = array();

                               $submit_vars["brandId"] = $brandId;

// Ну а это адрес, куда весь запрос наш полетит

                               $submit_url = "http://www.filter.com/application/get_models/";

Еще раз, для понимания: все эти данные здесь для примера. У каждого сайта они будут свои. У меня, почему то, при передаче Content-Length, такого же, как и в запросе браузера, приходил пустой ответ от сервера. Попробовал не передавать его – работает. Значит параметр не важный для запроса. А вот без этого : $snoopy->rawheaders["X-Requested-With"] = "XMLHttpRequest";

Приходил пустой результат.

С ним сайт отвечает - результат получен!!!

Шлем запрос и получаем результат:

if($snoopy->submit($submit_url,$submit_vars))
       {

// Если удачно залезли

$var = $snoopy->results;

// Тут к нам как раз и прилетел JSON, декодируем в массив

$vars = json_decode($var);

//Который потом разбираем

     foreach($vars as $value){
     $c=$value->app_model_id;
     $d=$value->app_model_name;

// Выводим список моделей

      echo '<option value="'.$c.'">'.$d.'</option>
       ';

// И пишем его в БД

       $sql = mysql_query("INSERT INTO `db_ 6`.`_car_model` (`car_model_id`, `car_model_brand_id`, `car_model_name`) VALUES ('$c', '$a', '$d')");
                                               }
                               }
                }             

       echo '</select>';
       echo '<input type="submit" id="btnAppSearch" name="btnAppSearch" value="Go"/> </form>';

                }

Как можно увидеть, таблица с моделями заполняется при первом выборе производителя. При повторном запросе по этому производителю модели будут прилетать из локальной БД. Ну а дальше:

 

else {

// Оказалось, что выбран и производитель и модель

Проделываем то же самое с get_years, get_eng_vol, дойдя до ягодки get_applications, отправив которой в запросе

                               $submit_vars = array();

                               $submit_vars["modelId"] = $selModel;

                               $submit_vars["year"] = $year;

                               $submit_vars["eng_vol"] = $eng_vol;


Получим в ответ заветный JSON c {Oil;Air;Fuel;Cabin;Trans}

 

http://idemitsu.to.net.ru/poisk.php - вот полученный вариант каталога, который можно встроить в сайт или в окно 1с продавца…

 

Всем удачи и успехов.

Парсер PHP каталоги

См. также

SALE! 20%

Автоматический заказ поставщику в 1С: загрузка прайсов и анализ цен поставщиков для УТ 10.3, УТ 11, КА2, УНФ, УПП, ERP, Розница 2

Бюджетирование и планирование Оптовая торговля Розничная торговля Логистика, склад и ТМЦ Анализ продаж Платформа 1С v7.7 Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Управление торговлей 10 1С:Розница 2 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Беларусь Украина Россия Казахстан Управленческий учет Платные (руб)

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

28500 22800 руб.

21.04.2017    90160    105    39    

190

ЕГАИС++. Опт, производство, импорт

Оптовая торговля Розничная торговля Обмен с ГосИС Платформа 1С v8.3 1С:Управление торговлей 10 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Рестораны, кафе и фаст-фуд Россия Бухгалтерский учет Управленческий учет Акцизы Платные (руб)

Полнофункциональное расширение (ранее известное как Модуль 1С-ЕГАИС) для взаимодействия типовых конфигураций 1С и ЕГАИС, предоставляющее максимум возможностей по работе с УТМ. Получение и отправка ТТН, отправка акта о постановке на баланс и акта о списании. Получение остатков. Загрузка и сопоставление номенклатуры и контрагентов. Оправка в ЕГАИС отчетов о производстве и импорте.

8970 руб.

15.12.2015    165949    678    362    

385

Обмен с системой ЦРПТ (Универсальная конфигурация ХамелеонЦРПТ + маркировка табака, обуви, одежды, лекарств, фото, молока, духов(парфюма), питьевой воды, велосипедов и шин)

Оптовая торговля Розничная торговля Обмен с ГосИС Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Россия Бухгалтерский учет Управленческий учет Платные (руб)

Данная публикация создана для помощи разработчикам, интеграторам и другим заинтересованным лицам по настройке системы маркировки обуви, одежды, лекарств, табака, фото, молока, духов(парфюма), питьевой воды, велосипедов и шин. Смело задавайте нам вопросы по работе с ЦРПТ, GS1, ЭДО, Национальным каталогом, мы накопили достаточно большую базу знаний по данным темам и готовы ответить на все Ваши вопросы.

104000 руб.

18.03.2019    110318    34    114    

178

Обмен с системой Меркурий через Web + Ветис.API для любых конфигураций (универсальная конфигурация Хамелеон Меркурий)

Оптовая торговля Производство готовой продукции (работ, услуг) Розничная торговля Обмен с ГосИС Платформа 1С v8.3 Конфигурации 1cv8 Сельское хозяйство и рыболовство Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Рестораны, кафе и фаст-фуд Пищевая промышленность Россия Бухгалтерский учет Управленческий учет Платные (руб)

Универсальная конфигурация Хамелеон Меркурий для взаимодействия с системой Меркурий(тестовый+рабочий+демо контур) может использоваться для интеграции в любую конфигурацию на базе 1С, версии ПРОФ и выше. Основное отличие от других решений - работа через веб-интерфейс и API 2.0(API 2.1). Для удобства реализован общий интерфейс в виде обработки, схожей с интерфейсом Меркурий, но возможностей гораздо больше, т.к. при интеграции в Вашу учетную систему, можно на основании Ваших справочников и документов, создавать соответствующие документы и справочники в системе Меркурий и наоборот.

104000 руб.

08.11.2017    120851    296    138    

392

Простое ценообразование (установка цен номенклатуры) для 1С 8.3 (УТ 11 / ERP 2 / КА 2 / Розница 2) + (УТ 10.3 / УПП / КА 1 / Розница 1)

Оптовая торговля Розничная торговля Ценообразование, анализ цен Платформа 1С v8.3 Управляемые формы 1С:Комплексная автоматизация 1.х 1С:Управление торговлей 10 1С:Розница 2 1С:Управление производственным предприятием 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:CRM ПРОФ, КОРП Управленческий учет Платные (руб)

Есть проблемы с расчетом и установкой цен на товары? Универсальная подсистема для ценообразования в 1С поможет навести порядок с ценами! Механизм позволяет задавать произвольные правила расчета колонок цен для разных групп товаров и легко их изменять. Может автоматически (по расписанию) обновлять цены в 1С и выполнять проверку наличия и корректности цен на все товары.

30000 руб.

13.11.2017    77898    40    11    

46
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. dock 44 21.06.17 11:58 Сейчас в теме
И сразу вопрос: а откуда мы узнали имя базы, логин и пароль ? а потом еще и структуру базы... имена таблиц...
2. user775227 2 21.06.17 14:35 Сейчас в теме
(1) Как откуда? Из головы... Придумали... Вы считаете мне было нужно в статье про парсер описывать работу с Мускулем? Я посчитал это лишним, простите.
3. dock 44 21.06.17 16:54 Сейчас в теме
(2)

Получается, что вы делаете:
1) Создаем локальный сайт: база + немного кода PHP

Вот тут не хватает описания структуры БД.

2) Наполняем базу данными и выводим результаты
а) "Производители" - откуда взяли список производителей ?
б) модели - если локальная БД пуста, получаем с сайта производителя (описано в статье)
г) год выпуска + кузов - если локальная БД пуста, получаем с сайта производителя (описано в статье)

Итак, замечания:

1)
Еще раз, для понимания: все эти данные здесь для примера. У каждого сайта они будут свои.
с этого нужно было начинать статью :) Да, про "Еще раз..." - так и не увидел первого упоминания :)

2) Сайт производителя: указан только в примере кода - нигде четко не указано, с каким именно сайтом работаете. А учитывая Ваши же слова (приведены выше) - с этого нужно было начинать статью!
3)
Вы считаете мне было нужно в статье про парсер описывать работу с Мускулем?


описывать работу с мускулем не стоит, но вот описать структуру Вашей базы - нужно.

4) А где полный исходник ?
5. user775227 2 21.06.17 18:15 Сейчас в теме
Спасибо за замечания, но будьте внимательны. Второй абзац гласит:
"Все, что будет написано ниже, применимо не только к автомобильным фильтрам, а и к компьютерным комплектующим и прочим товарам, новостям, статьям, блогам."
Вы считаете, что здесь не хватает фразы: "Поэтому локальная база, запросы к сайту и весь программный код у каждого будет свой"?
Проблема заключается в том, что даже поисковики не умеют правильно работать с сайтами каталогов, применяющих ajax и json.
Поэтому найти в Яндексе или Гугле какое масло залить или какой фильтр поставить - великая проблема. Дает ссылки на форумы, но не производителей.
Зачем описывать структуру БД, состоящей из плоских таблиц? я описал первые две. Остальные вытекают из них...
По поводу подопытного сайта... Ни один парсер не скажет, что именно он парсит. Ибо рискует быть забаненным. Мой парсер не использует циклов, поэтому не дает нагрузку на сервер. Инфа в локальную базу пишется только после первого открытия страниц с текущими данными.
Страницы открывают поисковики, примерно по 10 - 100 в день. Это я вижу по логам, которые пишу в отдельную таблицу.
Поэтому каждый день в локальную базу добавляется 5-50 машин. Основные, ходовые модели уже давно пробиты моими менеджерами...
Для чего Вам полный исходник? Каждый следующий шаг копирует предыдущий, меняется только запрос и ответ...
8. dock 44 23.06.17 15:19 Сейчас в теме
(5)
Для кого пишется статья ? Если для новичка - то слишком запутано, для не новичка - бесполезна.

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


ИМХО, эта фраза вообще лишняя и вводит в заблуждение.
при прочтении "Все, что будет написано ниже, применимо не только к ..." в голове у читающего возникает мысль: "О! мне сейчас расскажут как сделать универсальную всеядную штуковина на все случаи жизни!"


Вы считаете, что здесь не хватает фразы: "Поэтому локальная база, запросы к сайту и весь программный код у каждого будет свой"?


Я считаю, что не хватает фразы: "Рассмотрим на примере сайта производителя Имя_Сайта."
И не забыть явно напомнить: "У каждого производителя/сайта своя структура данных и эта структура может изменяться".

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

Описание таблиц где-то спряталось в тексте...
Опять таки, если для новичка (а судя по содержанию, именно для новичка) - структура базы обязательна!
Не нужно прилагать полные таблицы с описанием полей, типов и т.д., достаточно скриншота из PHPMyAdmin.

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

"Полный" - это я немного погорячился, достаточно рабочего. Какая бы ни была хорошая и подробная статья, рабочий пример намного более нагляден.
И да, можно стартмани заработать :)
10. user775227 2 24.06.17 06:56 Сейчас в теме
(8) Эту статью я написал как раз для одного единственного новичка в парсинге, который никак не мог разобраться как парсить динамическую страницу.
И он, в результате, написал весьма не плохой продукт, который по заданным параметрам находит нужный товар на нескольких заданных сайтах. С чем не справляется ни один поисковик, которому надо указать не параметры, а текст. Да и то
https://www.google.ru/#newwindow=1&q=toyota+allion+2003+1.8+oil+filter
выдаст всякую ерунду, не ответив на главный вопрос.
Весь программный код, который я выложил, полностью рабочий. Заменены только адреса, название базы и пароль.
На форумах по РНР это весьма применимая практика. Но, к сожалению, там я не нашел статей, как получить динамическую инфу, что и описал.
Что именно запутанно в статье? Чего Вы так упорно добиваетесь имя сайта? Человек, который разбирается в теме, его легко определит, а парсеры, ибо это не вполне легально, имя сайта не скажут. И не будет меняться структура у динамического каталога. Она напрямую зависит от базы данных. Это не одно и то же, что парсить статические страницы через регулярки, чем я занимался лет этак 20 назад. В свое время был забанен на тот момент крупнейшими интернет магазинами, ибо парсил в лоб по циклу.
И скриншот из РНРМуАдмин сделать не реально, ибо в моем случае я использую не отдельную базу, а огромную базу интернет магазина, куда собирают инфу десятки парсеров. Фотки, описания, отзывы. Светить это мне не надо.
Кстати, этот парсер в итоге не только фильтра подбирает, но и дополняет базу кроссов. Я к теме выложил скриншотик кроссов. Они тоже получаются парсингом.
По поводу придирок, Вы придирайтесь, мне интересно. Я не писатель и не программист... Поэтому интересно чужое мнение.
На форумах по РНР выкладываю длинный код - налетает стая его обкакивать, типа тут можно было процедур написать, а не повторять дважды текст, а тут нафига безусловный переход поставил?...
Смешные они, однако. Использование процедур, как вы считаете, не является ли случайно двойным безусловным переходом? Двойные стандарты даже в программировании. Процедуры нужно, а безусловные переходы нельзя... Как то так...
4. dock 44 21.06.17 17:03 Сейчас в теме
Как уже говорил, в исходнике страницы мы ничего не увидим, поэтому запускаем встроенные в браузер средства отладки. Я пользовался оперой. Поэтому правый клик => посмотреть код элемента. Переходим на вкладку Network, где переходим в под-вкладку XHR. Тут то и отображаются «подпольные» сетевые действия, которые нужно внимательно изучить. Выбираем в списке автомобиль (я выбрал TOYOTA) и кликаем «дальше»… В окне браузера появляется список с моделями, а на нашей вкладке мы видим что добавилась строка get_models/. Выбрав ее, видим много интересного. Видим адрес, по которому браузер отправлял запрос. Дальше нас интересует информация, которую браузер отправлял на сайт: Request headers. И данные, которые браузер передал: FormData. Snoopy.class - нам в помощь.


в от к этому тексту как минимум три скрина бы...
7. user775227 2 23.06.17 08:44 Сейчас в теме
(4)
Прикрепленные файлы:
6. user775227 2 21.06.17 18:18 Сейчас в теме
Ок, только уже послезавтра. Уезжаю в командировку. Послезавтра повешу Вам скрины с какого нибудь из сайтов, на которых тренировался.
Подбор масла Мотюль пойдет? Там хорошо все видно< как изучать подпольные сетевые действия браузера,,,
9. dock 44 23.06.17 15:20 Сейчас в теме
Нда... вот сижу и думаю... человек написал статью, а я придираюсь...
Вы уж извините, тяжело быть перфекционистом :)
11. dock 44 27.06.17 16:32 Сейчас в теме
ИМХО, после всех этих комментариев уже и добавить нечего :)
12. user1782657 02.02.23 11:47 Сейчас в теме
День добрый! А если у нас задача такая - углядеть демпингеров на наш бренд?
К примеру, я вношу список URL с товарами в модуль, а он вылавливает мне цену (по 100 сайтам, к примеру, и выгружает ее в Excel). Так возможно? Спасибо
Оставьте свое сообщение