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

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

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

8970 7176 руб.

15.12.2015    170793    955    364    

400

SALE! 20%

Загрузка и выгрузка в Excel Оптовая торговля Печатные формы Бухгалтер Пользователь Платформа 1С v8.3 Управляемые формы Платформа 1C v8.2 Конфигурации 1cv8 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Розница 2 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Управление холдингом 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Бухгалтерский учет Управленческий учет Платные (руб)

Универсальная обработка для загрузки документов из Excel в 1С одним нажатием. Не требует указания параметров (номера колонок, номер первой строки таблицы и т.д.) и предварительной настройки. Просто выбираете файл Excel, документ 1С и нажимаете кнопку "Загрузить". Обработка сама находит таблицу в файле Excel, необходимые для загрузки данные в ней (номенклатура, количество, НДС, цена, сумма) и загружает ее в 1С. Вместе с номенклатурой может найти контрагента, номер и дату документа, штрих-коды, серии ГТД, страну и т.д. Распознает документы ЛЮБОЙ ФОРМЫ (УПД, ТОРГ-12, заказ, отчет комиссионера и т.д.). Не требует MS Office. Для поиска таблиц используются методы эвристического поиска. Загружает только то, что нужно, т.е. пропускает повторы шапки таблицы, заголовки, промежуточные итоги, подписи и т.д. Содержит модуль работы с электронной почтой и api-загрузчик отчетов о продажах маркетплейсов.

6000 5100 руб.

09.11.2016    234100    1062    898    

1003

SALE! 10%

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

Можно проверить до покупки, оставьте заявку! Воспользовались более 268 компаний! Перенос данных из УТ 10.3 в УТ 11 | из УТ 10.3 в КА 2 | из УТ 10.3 в ERP. Предлагаем качественное и проверенное временем решение для перехода с УТ 10.3. Можно перенести начальные остатки, нормативно-справочную информацию и все возможные документы. При выгрузке можно установить отбор по периоду, организациям и складам. При выходе новых релизов конфигураций 1C оперативно выпускаем обновление переноса данных.

55778 50200 руб.

24.04.2015    194949    150    243    

280

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

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

44000 руб.

08.11.2017    122941    292    140    

398

Управление взаимоотношениями с клиентами (CRM) Оптовая торговля Розничная торговля Пользователь Платформа 1С v8.3 Оперативный учет Управляемые формы 1С:Управление торговлей 10 1С:Розница 2 Россия Управленческий учет Платные (руб)

Подсистема призвана упростить и автоматизировать процесс расчета и начисления бонусов покупателей. Бонусная система работает с конфигурациями 1С:УТ 10.3, 1С:Розница. Механизм реализован в начале 2013г. и работает до сих пор с постоянными совершенствованиями.

30000 руб.

02.11.2015    112284    102    87    

185
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
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). Так возможно? Спасибо
Оставьте свое сообщение