Предположим, что нам нужно спарсить несколько страниц интернет-магазина, например, для отслеживания цен на какой-то список товаров. Это можно организвать либо через цикл в скрипте PHP, либо можно сделать несколько AJAX запросов к PHP парсеру без перезагрузки основной страницы. Второй вариант сегодня подробно рассмотрим в данной статье.
Вначале хотел дописать парсер из предыдущей статьи, но потом решил отдельный проект сделать, чтобы не нагромождать всё в одну кучу.
AJAX запросы будем отправлять с помощью JS библиотеки jQuery. Чтобы не таскать за собой лишние файлы подключим её с серверов Google.
В проекте будет 2 файла: index.html c HTML и JS кодом, и ajax-parser.php для формирования и отправки запросов на загрузку страниц с помощью расширения cURL. Специально, что в этом проекте, что в предыдущих, не делю код на разные файлы. Считаю так удобнее в процессе первого знакомства воспринимать общие алгоритмы работы парсеров.
Код index.html:
<!doctype html> <html> <head> <title>Парсер информации на Gearbest.com</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <!--meta name="robots" content="noindex,nofollow"--> <script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js" type="text/javascript"></script> </head> <body> <style> .wrapper { max-width: 600px; margin: 0 auto; } h1 { text-align: center; } .action_form { max-width: 560px; margin: 0 auto; } .action_form input, .action_form textarea { width: 100%; } .action_form textarea { min-height: 100px; } input[type="text"] { font-size: 1em; min-height: 36px; box-sizing: border-box; } input[type="submit"], input[type="button"] { padding: 8px 12px; margin: 12px auto; font-size: 1.2em; font-weight: 400; line-height: 1.2em; text-decoration: none; display: inline-block; cursor: pointer; border: 2px solid #007700; border-radius: 2px; background-color: transparent; color: #007700; } input[type="submit"]:hover, input[type="button"]:hover { background-color: #009900; color: #fff; } .result { border: 1px dotted #000; width: 100%; height: auto; overflow-y: auto; margin: 0px auto; padding: 10px; } .copyright { text-align: center; } .copyright a { color: #000; } .copyright a:hover { text-decoration: none; } .red { color: #770000; } .green { color: #007700; } </style> <div class="wrapper"> <h1>Парсер цены товара на Gearbest.com</h1> <form id="action_form" class="action_form" action="ajax-parser.php" method="post"> <textarea type="text" id="gearbest_urls" name="gearbest_urls"></textarea> <input type="button" id="btn_action_price" name="btn_action_price" value="Цены" /> </form> <div id="result" class="result"></div> <div id="errors_block" class="errors_block"></div> <div class="copyright">© Идея и реализация - <a href="https://seorubl.ru/" target="_blank" title="Записки Предприимчивого Человека" rel="generator">ПЧ</a> // 22.04.2017 г.</div> </div> <script type="text/javascript"> jQuery(document).ready(function($) { $('#btn_action_price').click(function() { var gearbest_urls = $("#gearbest_urls").val().split('\n'); var action_url = $("#action_form").attr('action'); if(gearbest_urls) { $('#result').html(''); $('#errors_block').html(''); gearbest_urls.forEach(function(gearbest_url, i, arr) { var send_data = {gearbest_url: gearbest_url}; $.ajax({ type: "POST", url: action_url, data: send_data, success: function(msg){ msg = JSON.parse(msg); // Показываем результат парсинга $('#result').html($('#result').html() + "<p>[" + (i+1) + "] " + "<span>" + msg.price_list.price + "</span> <span>" + msg.price_list.currency + "</span> - <span>" + gearbest_url + "</span></p>").hide().fadeIn('slow'); msg.errors.forEach(function(error, j, errors_arr) { $('#errors_block').html($('#errors_block').html() + "<p>[" + (i+1) + "] " + msg.errors + "</p>"); }); } }); }); } else { $('#errors_block').html($('#errors_block').html() + "<p>Введите адреса товаров</p>").hide().fadeIn('slow'); } return true; }); }); </script> </body> </html>
Код ajax-parser.php
<?php Error_Reporting(E_ALL & ~E_NOTICE); mb_internal_encoding("UTF-8"); set_time_limit(0); // Попытка установить своё время выполнения скрипта /* --- 1 --- Инициализируем переменные для запроса */ $time_start = time(); $gearbest_url = ""; $charset = "UTF-8"; // Исходная кодировка страницы $uni_name = date("d-m-Y-H-i-s", time()); /* --- 1.1 --- Переопределяем переменные на основе GET или POST параметров */ if(isset($_REQUEST['gearbest_url'])) { $gearbest_url = trim($_REQUEST['gearbest_url']); } /* --- 1.2 --- Запросы при помощи cURL */ /* --- 1.2.1 --- Загрузка страницы при помощи cURL */ function curl_get_contents($page_url, $base_url, $pause_time, $retry) { /* $page_url - адрес страницы-источника $base_url - адрес страницы для поля REFERER $pause_time - пауза между попытками парсинга $retry - 0 - не повторять запрос, 1 - повторить запрос при неудаче */ $error_page = array(); $ch = curl_init(); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0"); curl_setopt($ch, CURLOPT_COOKIEJAR, str_replace("\\", "/", getcwd()).'/gearbest.txt'); curl_setopt($ch, CURLOPT_COOKIEFILE, str_replace("\\", "/", getcwd()).'/gearbest.txt'); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // Автоматом идём по редиректам curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); // Не проверять SSL сертификат curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); // Не проверять Host SSL сертификата curl_setopt($ch, CURLOPT_URL, $page_url); // Куда отправляем curl_setopt($ch, CURLOPT_REFERER, $base_url); // Откуда пришли curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Возвращаем, но не выводим на экран результат $response['html'] = curl_exec($ch); $info = curl_getinfo($ch); if($info['http_code'] != 200 && $info['http_code'] != 404) { $error_page[] = array(1, $page_url, $info['http_code']); if($retry) { sleep($pause_time); $response['html'] = curl_exec($ch); $info = curl_getinfo($ch); if($info['http_code'] != 200 && $info['http_code'] != 404) $error_page[] = array(2, $page_url, $info['http_code']); } } $response['code'] = $info['http_code']; $response['errors'] = $error_page; curl_close($ch); return $response; } /* --- 1.3 --- Функции для Gearbest.com */ /* --- 1.3.1 --- Парсинг цены */ function get_gearbest_price($gearbest_url) { /* $gearbest_url - адрес страницы товара на Gearbest */ $res_arr = array(); $res_arr['price_list'] = array(); $res_arr['errors'] = array(); $base_url = "https://www.gearbest.com"; $response_arr = curl_get_contents($gearbest_url, $base_url, 5, 1); $page = $response_arr['html']; $page_code = $response_arr['code']; $res_arr['errors'] = array_merge($res_arr['errors'], $response_arr['errors']); //file_put_contents('page.txt', $page); //$page = file_get_contents('page.txt'); if(!empty($page) && $page_code == 200) { if($charset != "UTF-8") { $page = iconv("WINDOWS-1251", "UTF-8//IGNORE", $page); } $buffer = array(); $regexp = "/<meta property=\"og:price:amount\" content=\"(.*)\"\/>/Us"; preg_match($regexp, $page, $buffer); $res_arr['price_list']['price'] = $buffer[1]; $regexp = "/<meta property=\"og:price:currency\" content=\"(.*)\"\/>/Us"; $buffer = array(); preg_match($regexp, $page, $buffer); $res_arr['price_list']['currency'] = $buffer[1]; } else { $res_arr['price_list']['price'] = 0; $res_arr['price_list']['currency'] = 'nodata'; $res_arr['errors'][] = 'Ошибка загрузки страницы'; } return $res_arr; } /* --- 2 --- Получение контента из сайта Gearbest */ if(!empty($gearbest_url)) { $gearbest_url = trim($gearbest_url); $din_url = $gearbest_url; $res_arr = get_gearbest_price($din_url); } else { $res_arr['error'][] = "Не задан адрес страницы с товаром"; } /* --- 3 --- Вывод результатов работы парсера в JSON формате*/ echo json_encode($res_arr); ?>
В код скриптов добавил подробные комментарии. Общий алгоритм работы парсера следующий. На странице после нажатия на кнопку цены мы разбиваем список адресов товаров в массив. Дальше в цикле формируем и отправляем с помощью AJAX несколько POST запросов к файлу ajax-parser.php.
В этом файле выполняется PHP скрипт, который с помощью функций cURL получает страницу по нужному адресу с сайта gearbest.com и далее из полученного текстового содержимого посредстом регулярных выражений выделяет нужные нам данные. Потом полученные данные добавляются в массив, преобразуются в JSON формат и передаются в ответ AJAX функции. Полученный ответ преобразуется средствами JavaScript из JSON строки в объект и спарсенные данные выводятся в нужные теги.
Я специально добавил в список один некорректный адрес, чтобы посмотреть, как будут выводиться ошибки. Адреса товаров отправляются на обработку в порядке записи. А ответы приходят в порядке их получения. Именно поэтому ошибочный адрес был получен первым, 404 страница формируется сервером gearbest.com быстрее, чем страница товара.
С помощью AJAX можно делать наглядные интерактивные интерфейсы у парсеров, да и других приложений и сайтов. Вариант парсинга в цикле без AJAX мы позже рассмотрим на примере сбора фото товаров.
В следующей статье я продолжу рассказывать об использовании технологии AJAX в задачах парсинга сайтов. Мы рассмотрим, как получить данные, которые на страницу сайта-источника подгружаются асинхронно, и в HTML коде изначально нужного текста просто нет.
У меня почему-то не парсится. Выдает «null null», подскажи пожалуйста в чем может быть причина.
Разные причины могут быть. Сейчас попробовал сымитировать действия простого пользователя, прямо из статьи скопировал куски кода, создал нужные файлы, выбрал произвольные товары… И парсер нормально работает.
Если есть большое желание разобраться, то можем связаться по скайпу, разберём возникающие ошибки.
Разобрался, на хосте проблемы, выдает 500 ошибку при обращении к скрипту. На локалке все работает.
Разобрался и с хостингом ) Всё оказалось банально, старая версия PHP, обновил и все гуд.
Отлично, что разобрались и всё работает как надо.
Все работает, разобрался.
В чем было дело? У меня такая же проблема.
Очень крутой блог.
Начал заниматься написанием парсера с нуля и тут на сайте именно то, что доктор прописал.
Все по полочкам, нормальным человеческим языком.
Спасибо автору. Здоровья тебе и добра.
Буду учиться, так как есть конкретные задачи и Ваши записки станут отправной точкой в моих задачах.
Спасибо вам за положительный комментарий. Будут какие-то конкретные вопросы по парсерам, чем смогу помогу.
Как раз стояла задача сверстать сайт с большим количеством реальных данных. Взял ваш код, настроил урлы и все работает «из коробки». Отличное решение, очень понравилось наглядность процесса!