Created
June 5, 2019 08:37
-
-
Save sidor1989/6e4747dafca763393a47cd7659385ad4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
В моей практике, проблема актуальности цен и наличия товаров на сайте стоит очень остро. Владельцы сайта физически не успевают обновлять каталог и доходило до того, что у одного из моих клиентов было порядка 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