Почему работа моего парсера забирает все ресурсы и вырубает сервер?

Здравствуйте. Помогите, пожалуйста, я запускаю свой парсер по крон, забираю им некоторую информацию с сайта моего поставщика и обрабатываю ее. Парсер запускается-то всего на 500 страниц товаров, у меня таких аж 8000 тысяч, но даже на 500 артикулов парсер съедает все ресурсы и приводит сервер в нерабочее состояние, к нему не подключится по ssh и все сайты отдают 500-сотые ошибки. Я понимаю, что скорее всего дело в том, что мой парсер не оптимизирован, так как сама я не разбираюсь в этом пока что, прошу совета, что тут следует переписать? Парсер сначала авторизуется на сайте поставщика, потому что только так видны остатки, а потом от имени авторизованного пользователя собирает информацию. Как соберет формирует запрос на обновление базы данных, запросы скидывает в массив, только в конце работы делается одно подключение к БД и выполняется запрос на обновление. У меня 1 Гб ОЗУ на сервере.

ini_set('max_execution_time', '10000');
set_time_limit(0);
ini_set('memory_limit', '768M');
ignore_user_abort(true);

require_once 'vendor/autoload.php';
require_once 'phpquery/phpQuery/phpQuery.php';

//УРЛ для выполнения авторизации
$url_auth = 'http://...';

//Заданный мною массив, где ключ это артикул товара, а значение его product_id в моем магазине
$massiv = [
"артикул поставщика" => "мой product_id",
...
]

//Объявляю массивы, которые могут быть заполнены впоследствии.
$existart = []; $existartstatus = []; $existartstatus2 = []; $notupdated = [];

//Создаю файлы, в которые буду записывать нужные мне значения по ходу работы
$file_result = 'not_added.txt'; if (file_exists($file_result)) unlink($file_result);
$file_result2 = 'empty.txt'; if (file_exists($file_result2)) unlink($file_result2);
$file_result3 = 'not_updated.txt'; if (file_exists($file_result3)) unlink($file_result3);

//Данная функция будет вызываться для парсинга каждой отдельной страницы товара для того, что авторизованным забрать содержимое страницы
function get_content($url) {
	$ch = curl_init($url);
	curl_setopt ($ch, CURLOPT_HEADER, 0);
	curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
	curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)");
	curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, false);
	curl_setopt ($ch, CURLOPT_POST, true);
	curl_setopt ($ch, CURLOPT_POSTFIELDS, array(
		'login' => '###',
		'pass' => '###',
	));
	curl_setopt ($ch, CURLOPT_COOKIEJAR, __DIR__ . '/cook.txt');
	curl_setopt ($ch, CURLOPT_COOKIEFILE, __DIR__ . '/cook.txt');
	curl_setopt ($ch, CURLOPT_TIMEOUT, 3000);
	curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 300);
	$res = curl_exec($ch);
	curl_close($ch);
	return $res;
}

$merged = "это массив со ссылками на карточки товаров, по которым нужно пройтись"

//Главная функция, отрабатывающая для каждой ссылки
function foreach_parser() {
	global $merged; global $massiv; global $existart; global $existartstatus; global $existartstatus2; global $notupdated; global $file_result; global $file_result2; global $file_result3;
	foreach ($merged as $page){
		$file = get_content($page);
		$doc = phpQuery::newDocument($file);
		$doc = pq($doc);

			$art = $doc->find('#r div.x div.xx div.xxx')->text();
			$art = str_replace("/"," ",$art);
			$art = trim($art);
					
			/* Тут еще выполняется несколько операций по нахождению значений и их обработки. Определяются переменные $stock, $status и прочие */
			
			//Проверяю содержится ли в моем заранее заданном массиве элемент с ключом, равным данному артикулу, если да, то для него забирается его значение		
			if (isset($massiv[$art])) {
				if ($status == "Preorder") {
					$value = $massiv[$art];
					$existart[] = "WHEN product_id = ".$value." THEN ".$stock;
					$existartstatus[] = "WHEN product_id = ".$value." THEN 'Под заказ'";
					$existartstatus2[] = "WHEN product_id = ".$value." THEN 24";					
				} else {
					$value = $massiv[$art];
					$existart[] = "WHEN product_id = ".$value." THEN ".$stock;				
				}
				$value2 = $massiv[$art];
				$notupdated[] = $value2;
			} else {
				//Элемента массива с таким ключом не найдено, значит записываем данный артикул в файлик
				$message = $art.PHP_EOL;
				file_put_contents($file_result, $message, FILE_APPEND);
			}
			
			echo $art." обработан! ";		
		$i++;
	}
	
	//Если мои массивы заполнились каким-то данными, тогда я сливаю их элементы в единую строку
	if($existart) {$existart_oneline = implode(" ", $existart);}
	if($existartstatus) {$existartstatus_oneline = implode(" ", $existartstatus);}
	if($existartstatus2) {$existartstatus2_oneline = implode(" ", $existartstatus2);}
	$massiv_onlyid = implode(",", $massiv);
	
	//Сравниваю изначально заданный мною массив с полученным в результате парсинга массивом для того, чтобы найти те товары, которые у меня в массиве (на сайте) есть, а в процессе работы парсинга не были задействованы, так я понимаю, какие остатки у меня не обновились.
	$mas_notupdated = array_diff($massiv, $notupdated);
	if ($mas_notupdated) { $mas_notupdated_txt = implode('`', $mas_notupdated); file_put_contents($file_result3, $mas_notupdated_txt); }
	
	//Подключаюсь к базе данных и выполняю запросы на обновление остатков и при необходимости других полей
	$linkmysql = mysqli_connect('localhost', 'xxx', 'xxx', 'xxx');	
	
	if (!$linkmysql) {
		$sqlconnecterror = "Ошибка: Невозможно установить соединение с MySQL.";
		exit;
	}
	if ($linkmysql) {		
		if($existart) {
			Первый запрос на обновление информации
		}
		if($existartstatus) {
			Второй запрос на обновление информации
		}

		mysqli_close($linkmysql);
	}
		
	phpQuery::unloadDocuments();	

}

$data = get_content($url_auth);
foreach_parser();


Парсер грузит оперативку до 99,9% и всё, дальше ничего не работает. Я поставила ему memory_limit', '512M', но он все равно забирает всю оперативную память. Как ему не позволять забирать все ресурсы?
  • Вопрос задан
  • 258 просмотров
Пригласить эксперта
Ответы на вопрос 3
heksen
@heksen
У вас в цикле стоит запрос curl. Когда вы делаете запрос, ответ от сервера может прийти, а может и нет, а память тем временем выделяется. Копайте в сторону асинхронного запроса curl. Я думаю здесь проблема.
Ответ написан
@synapse_people
$doc = phpQuery::newDocument($file);
это дерьмо лучше заменить нативным DOMDocument, скорее всего где-то там память и пропадает
Ответ написан
@oxidmod
Обрабатывайте ссылки по одной, а не все скопом
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы