Парсинг контента с интернет магазина
Ко мне часто обращаются знакомые с просьбами скачать какую-то информацию с другого сайта. Просьбы бывают абсолютно разными: от автоматизации вывода погоды/курса валют, до скачивания целых баз данных (посты с блогов, товары интернет магазинов и т. д.).
Утром мне пришёл СПАМ с рекламой одного парфюмерного магазина, и я решил отомстить им.
Сегодня мы будем парсить интернет-магазин.
англ. parse
1) синтаксический анализ, синтаксический разбор; грамматический разбор;
2) анализировать, разбирать.
То есть, применимо к нашей задаче, парсинг - это процесс анализа и разбора страницы с целью получения конкретных данных (в нашем случае - наименование и параметры товара).
Приступим.
Шаг 0. Предисловие.
Для выполнения поставленной задачи можно использовать разные языки программирования, кучу библиотек или трёхэтажные регулярные выражения. Можно, но не нужно. Давайте договоримся, что мы создадим предельно простую систему, используя элементарные регулярки.
Шаг 1. Изучаем URL.
Открываем
http://parfum-collection.ru/product/iris-ukioye/50325.html
http://parfum-collection.ru/product/boadicea-the-victorious/50340.html
Похоже, что на сайте настроено ЧПУ (Человеко-Понятные URL). Если уберем часть URL, получим ссылки, эквивалентные приведенным выше:
http://parfum-collection.ru/product/50325.html
http://parfum-collection.ru/product/50340.html
Последний сегмент - уникальный id товара.
Чтобы получить информацию о всех товарах на сайте нужно:
1. Зайти на главную страницу, считать все категории товаров.
1.1 Для каждой категории товаров - нужно получить название всех брендов.
1.2 Для каждого бренда получить список всех товаров.
1.3 Скачать информацию по всем товарам.
или
2. Запустить полный перебор товаров от 1 до 60000 (подбираем опытным путём).
Нас устраивает более легкий вариант - полный перебор. Перебор займет чуть больше времени, но гарантирует считывание всех товаров. И помните: мы пошли легким путём.
Шаг 2. Изучаем страницу с товаром.
Кликаем на произвольный товар, к примеру:
Откинув шапку, меню и подвал, получим примерно такую картину:
Опишем блоки (слева направо, сверху вниз):
1. Наименование товара
2. Путь товара (иерархия его категорий)
3. Блок с картинками
4. Цена. У одного товара может быть несколько вариантов поставки с разной ценой (выбирается из раскрывающегося списка)
5. Текстовое описание
6. Параметры товара
Остальная информация нам не интересна.
Заглянем в исходный код страницы. Весь HTML код хорошо приправлен комментариями. Нам же лучше. Нас интересует часть текста от
<!-- Товар /--> |
<!-- Характеристики товара #END /--> |
Основные элементы разметки опишем в следующем пункте.
Шаг 3. Парсим.
Создаем пустой файл parse.php.
max_execution_time - нужен, чтобы ограничить время выполнения скрипта. Из-за большого количества товара полный парсинг может занять значительный промежуток времени. Поэтому выставим 0 - не ограничено.
Страницу загружаем с помощью file_get_contents - как самый простой способ.
В итоге получается код:
<?php ini_set("max_execution_time", 0); $id = 50322; parse ($id); function parse ($id) { $file = file_get_contents("http://parfum-collection.ru/product/{$id}.html"); var_dump($file); } ?> |
Запустили. Порадовались контенту страницы. Лёд тронулся.
Дальше вырежем центральную часть с информацией о товаре.
preg_match("|<!-- Товар /-->(.*)<!-- Характеристики товара #END /-->|is", $file, $trunc); |
Если регулярное выражение сработало, то в $trunc[1] будет находиться нужный нам контент.
Запускаем. Получаем пустой результат. Проверяем регулярку - все верно. Смотрим на кодировку - ага: Кодировка сайта - UTF-8, а кодировка исходника - win-1251. Меняем кодировку. Запускаем и получаем вырезанный фрагмент. Далее продолжаем работать только с вырезанным фрагментом.
Получаем наименование товара:
Наименование товара находится между тегами . Это единственная пара тегов h1 на странице. Так что тут все легко.Получаем категорию товара: Категорию получаем в два этапа: сначала вырезаем div с id=path, после чего, с помощью функции explode, разбиваем на части фрагменты пути. Первый и последний элемент нам не нужны. Делаем им unset.
Получаем картинки товара:
Исследуем, как выводятся картинки. Вначале идет большая картинка. Под ней идет список миниатюр, при клике на которые происходит замена большой картинки. Нас интересуют участки кода, подчеркнутые красным. Они уникальны и по ним можно получить список картинок.Получаем цены и варианты товара:
Для этого нам надо написать два регулярных выражения. Первое - будет получать id и вариант товара. Второе - получать id и цену товара. Полученное заносим в один массив, и получаем связку из варианта товара и его цены.Получаем описание товара:
Тут все просто. В выделенном фрагменте находится искомый текст. Ничего сложного.Получаем характеристики товара:
Характеристики товаров занесены в таблицу, и разбиты построчно. Для начала получаем все строки (всё что находится междуШаг 4. Сохранение и другие фишки.
В статье не описано, как сохранить данные. Но людям, осилившим статью, не составит большого труда сохранить итоговый массив в БД. Так же в статье нет упоминания как сохранять картинки. Всё очень просто, и выглядит примерно так:
# для каждого товара, для каждой картинки товара: $file = file_get_contents($img_url); $handle = fopen('new_img_name',"x"); fwrite($handle, $file); fclose($handle); |
Какие недостатки у данной реализации? Самый главный недостаток - использование file_get_contents для получения исходного кода страницы с товаром. В случае подвисания сети - функция будет ожидать 30 секунд. Что бы управлять таймаутом соединения нужно использовать сокеты или CURL. Использование сокетов или curl усложняет работу скрипта (по крайней мере для новичка), но дает множество плюсов. Больше всего я люблю указывать в user-agent "Mozilla/5.0 (compatible; googlebot/2.1; +http://www.google.com/bot.html)"
PS.
Исходный код
Итоговая структура данных:
$data (array) | |||||||||||||||||||||||||||||||||||||||||
name | Gardenia | ||||||||||||||||||||||||||||||||||||||||
path |
| ||||||||||||||||||||||||||||||||||||||||
img |
| ||||||||||||||||||||||||||||||||||||||||
price |
| ||||||||||||||||||||||||||||||||||||||||
text |
| ||||||||||||||||||||||||||||||||||||||||
params |
|
А в чём состоит месть злым спамерам?
Однажды делал примерно то же самое, но прямо из терминала, используя wget, grep и sed. В конце все картинки обрезал, панорамировал и поменял яркость/контраст (imagemagic). Думаю, можно ещё использовать алгоритм цепей Маркова для микширования текстов описаний — где-то выкинуть пару слов, где-то поменять порядок следования.
В статье не упоминается, но:
1. Хозяева интернет магазина заказали SEO-раскрутку одной фирме.
2. Эта фирма занималась рассылкой спама, с парфюмерными предложениями.
3. Статья помогает интернет магазину поделится своей базой со всеми 🙂
4. В дополнении к этому — хостеру SEO компании было отправлено письмо с информацией о спаме, с предложением принять меры.
Оо да ты просто злой гений :))) Ещебы ссылки на магазин закрыл ноиндексом.
Статья хорошая. Спасибо.
Может подскажите как из такой ссылки _http://www.tissot.ua/tissot-i-id-i-37-i-product-i-T014.427.16.031.00-i-index.html выделить id для парсера? Или тут по другой схеме нужно парсить?
>Запустили. Порадовались контенту страницы. Лёд тронулся.
как вы это делаете?
_http://www.tissot.ua/tissot-i-id-i-38-i-product-i-T014.427.16.031.00-i-index.html
Большую часть URL можно удалить. В итоге ссылки на страницу с товаром имеют вид:
_http://www.tissot.ua/tissot-i-id-i-38
Меняя последнюю цифру мы получаем разные товары.
Что именно?
ну как происходит механизм парсинга? Он с сайта запускается или …? Если это доступно лишь опытным кодерам, то я не буду приставать)))
@Miroslav
Я пишу парсеры на PHP или Perl. Это интерпретируемые языки. Что бы запустить такой скрипт нужен веб-сервер. Подойдет и локальный. Например denwer или Open Server.
Если вы задаете такие вопросы, то написание парсеров пока не для Вас.
Научитесь азам. Попробуйте парсить элементарные вещи (курс валют или погоду). А дальше разбирайтесь с более сложными задачами.
запускал локальный сервер, но лишь для того, чтобы сайт собрать. Denwer
а так вы правы, наверное, это не для меня… Не готов
А как парсить результаты поиска на сайте, если URL не отражает условий поиска (по крайней мере, полностью). Например, здесь
http://212.50.98.101/findtour-ag/Extra/QuotedDynamic.aspx
Результаты выдачи можно получить отправив POST запрос по адресу формы. Запустите FireBug и исследуйте какие запросы посылает форма при отправке. Попробуйте послать аналогичный запрос. Если все пройдет успешно — вы получите блок с таблицей.
Класс, спасибо 🙂
У меня на локальном OpenServer функция file_get_contents вызывает ошибку. На бесплатном хостинге пишет Boolean False. В чем может быть проблема? Спасибо.
Попробовал изменить цель (сайт), получилось. А вот на нужном мне сайте не работает. Это защита у них такая от парсинга или что?
failed to open stream: HTTP request failed! HTTP/1.0 500 Internal Server Error in C:\OpenServer\domains\domain\test.php on line 9