Skip to content

Instantly share code, notes, and snippets.

@sidor1989
Created June 5, 2019 08:37
Show Gist options
  • Save sidor1989/6e4747dafca763393a47cd7659385ad4 to your computer and use it in GitHub Desktop.
Save sidor1989/6e4747dafca763393a47cd7659385ad4 to your computer and use it in GitHub Desktop.
В моей практике, проблема актуальности цен и наличия товаров на сайте стоит очень остро. Владельцы сайта физически не успевают обновлять каталог и доходило до того, что у одного из моих клиентов было порядка 70% отказов от сделанных заказов по этой причине.
В комплекте с miniShop2 идет скрипт для обновления каталога из файла csv, но чаще мне приходилось синхронизировать именно с сайтом поставщика, поэтому я хочу поделиться небольшим скриптом, который это и делает.
Для парсинга страницы я использовала библиотеку phpQuery в виду ее простоты: запросы очень похожи на синтаксис css и jQuery.
Сам код с комментариями:
<?php
echo '<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">';
//Подключаем MODx
define('MODX_API_MODE', true);
require_once dirname(dirname(__FILE__)) . '/core/config/config.inc.php';
require_once MODX_BASE_PATH . 'index.php';
//Функция для капитализации русского текста (опционально)
function ucfirst_utf8($stri){
if($stri{0}>="\xc3")
return (($stri{1}>="\xa0")?
($stri{0}.chr(ord($stri{1})-32)):
($stri{0}.$stri{1})).substr($stri,2);
else return ucfirst($stri);
}
//Проверка на админа
if (!$modx->user->isAuthenticated('mgr')) {
$modx->sendUnauthorizedPage();
}
//Подключаем phpQuery
require_once 'phpQuery.php';
//Base URL для распарсиваемой страницы для подстановки в ссылки
$url='http://www.brialdi.ru';
//Ссылка для парсинга
$link='http://www.brialdi.ru/shop/messenger_bags/?SHOWALL_3=1';
//ID производителя
$vendor=12;
//ID родителя
$parent=541;
//Запускаем парсер
phpQuery::newDocumentFileHTML($link);
//Инициализируем счетчики обновленных позиций, созданных и ошибок
$upd=0;
$cr=0;
$er=0;
echo "<pre>";
$create=true;
//Публиковать ли создаваемые ресурсы: можно передать GET или POST запрос
$published=isset($_REQUEST['published'])?$_REQUEST['published']:1;
$idx=0;
//Разбивка по 20 элементов для выполнения кусками
$begin=isset($_REQUEST['begin'])?$_REQUEST['begin']:0;
$offset=isset($_REQUEST['begin'])?($_REQUEST['begin']+20):20;
//Основной цикл: проходимся по всем элементам с классом .catalog-section-item (подставить свое)
foreach(pq("div.catalog-section-item:gte(".$begin.")") as $row){
//Получаем ссылку на страницу товара (в моем случае это ссылка с классом pr_hr)
$ilink= $url.pq($row)->find("a.pr_hr")->attr("href");
$have=true;
//Определяем наличие: в моем случае к элементу добавляли класс label-not-available
if(pq($row)->find("span:first-child")->attr("class")=="label-not-available"){
$have=false;
}
//Если со ссылкой все в порядке-обрабатываем
if(!empty($ilink)){
echo "Найден предмет:".pq($row)->find("a.pr_hr")->text()."\n\tЗагружаю:".$ilink."\n";
//Парсим внутреннюю ссылку
$doc=phpQuery::newDocumentFileHTML($ilink);
//Вытаскиваем артикул и обрабатываем его
$art=str_replace("Артикул: ","",pq("div.pr_det_top>div.left.l_1>div:first-child")->text());
//Вытаскиваем материал
$mat=ucfirst_utf8(trim(str_replace("Материал: ","",pq("div.pr_det_top>div.left.l_1>div:nth-child(2)")->text())));
//Ищем товар с таким артикулом в базе нашего сайта
$r = $modx->getObject("msProductData",array("article"=>$art));
if($r){
//Если есть, то обновляем
$id=$r->get("id");
//Получаем страницу товара
$page = $modx->getObject('modResource', $id);
$page->set("parent",$parent);
echo "\t\tРесурс есть:".$page->get("pagetitle")."\n";
echo "\t\t\t ".($have?"Есть":"Нет")." в наличии.\n";
//Устанавливаем ТV наличия
$page->setTVValue("have",($have?1:0));
//Сохраняем страницу товара
$page->save();
//Вытаскиваем цену
$price=floatval(preg_replace("/\s/","",str_replace(" руб.","",pq("#pr_price")->text())));
//Ставим цену
$r->set("price",$price);
//Сохраняем msProduct
$r->save();
//Проверяем, еть ли картинки у товара
$_img=$r->get('image');
if($r->get('image')==''){
echo "Нет изображения. Закачиваю\n";
//Закачиваем и добавляем изображения, если их нет
foreach(pq("ul#mycarousel a.loop_zoom") as $a){
$img="http:".pq($a)->attr("href");
$vup=$img;
$v='/assets/uploads/'.md5($img).'.jpg';
echo "Закачиваю файл $img\n";
$image = str_replace('//', '/', MODX_BASE_PATH . $v);
$ch = curl_init($vup);
$fp = fopen($image, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
$response = $modx->runProcessor('gallery/upload',
array('id' => $r->get("id"), 'name' => $v, 'file' => $image),
array('processors_path' => MODX_CORE_PATH.'components/minishop2/processors/mgr/')
);
//Сбрасываем ошибки процессора, чтобы вызывать несколько подряд
$modx->error->reset();
}
}
upd++;
}else{
//Создаем ресурс, артикула в базе нет
echo "\t\tРесурса нет. Создаю...\n";
//В моем случае слова в названии товаров начинаются с большой буквы, вытаскиваем и преобразовываем
$name=mb_convert_case(pq("h1")->text(), MB_CASE_TITLE, "UTF-8");
//Вытаскиваем размер
$size=str_replace("х"," х ",str_replace("Размеры: ","",pq("div.size")->text()));
//Вытаскиваем цвет
$color=str_replace("Цвет: ","",pq("div.pr_det_top>div.left.l_1>div:nth-child(3)")->text());
//Вытаскиваем описание
$content=pq("div.pr_desc")->text();
//Вытаскиваем цену
$price=floatval(preg_replace("/\s/","",str_replace(" руб.","",pq("#pr_price")->text())));
//Делаем массив из всех параметров
$dt=array("published"=>$published,"new"=>1,"pagetitle"=>$name,"price"=>$price,"parent"=>$parent,"class_key"=>"msProduct","size"=>'["'.$size.'"]',"color"=>'["'.$color.'"]',"article"=>$art,"content"=>$content,"vendor"=>$vendor,"alias"=>$art);
//Тут я добавляю характеристики товара в TV MIGX
$aspecs=array();
$lidx=1;
foreach(pq("div.pr_text_b ul li") as $li){
$aspecs_['MIGX']=$lidx;
$aspecs_['text']=trim(pq($li)->text());
$aspecs[]=$aspecs_;
$lidx++;
}
$specs=json_encode($aspecs);
//Опять скидываем ошибки процессора на всякий случай
$modx->error->reset;
//Создаем ресурс
$resp=$modx->runProcessor('resource/create',$dt);
if(!$resp->isError()){
$resource=$resp->getObject();
//Если все прошло успешно, то добавляем TV
$page=$modx->getObject("msProduct",array("id"=>$resource['id']));
$page->setTVValue('mat',$mat);
$page->setTVValue('spec',$specs);
//Сохраняем страницу
$page->save();
//Закачиваем картинки
foreach(pq("ul#mycarousel a.loop_zoom") as $a){
$img="http:".pq($a)->attr("href");
$vup=$img;
$v='/assets/uploads/'.md5($img).'.jpg';
echo "Закачиваю файл $img\n";
$image = str_replace('//', '/', MODX_BASE_PATH . $v);
$ch = curl_init($vup);
$fp = fopen($image, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
//Добавляем картинки к галерее
$response = $modx->runProcessor('gallery/upload',
array('id' => $resource['id'], 'name' => $v, 'file' => $image),
array('processors_path' => MODX_CORE_PATH.'components/minishop2/processors/mgr/')
);
$modx->error->reset();
}
//Увеличиваем счетчик успешно созданных элементов
$cr++;
}else{
//Если случилась ошибка добавления - выводим ее и увеличиваем счетчик ошибок
echo $resp->getMessage();
$er++;
}
}
}
}
//Выводим счетчики
echo "Создано: ".$cr." ресурсов";
echo "\n";
echo "Обновлено: ".$upd." ресурсов";
echo "\n";
echo "Ошибок при создании: ".$er." ресурсов</body></html>";
Вот, собственно и весь код. При желании его можно доработать и запускать по расписанию, или сделать для него симпатичную обвязку с прогресс-баром.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment