Парсер на PHP с записью контента в БД

Парсер на PHP с записью контента в БД

Нескольким читателям моего блога было интересно узнать «как объединить крон, базу данных и php парсер».
Я постарался написать максимально простой и лаконичный скрипт, чтобы любой новичок смог в нём разобраться. Он состоит всего из одного файла index.php и 50 строк кода.

Я использовал 2 библиотеки:

  • RedBean PHP, которая упрощает работу с БД и защищает от SQL инъекций -> читать подробнее
  • phpQuery — порт jQuery на PHP, который позволяет добираться до нужных блоков в дебрях документа

Парсить в учебных целях мы будем один сайт о моде и красоте. Остановимся мы только на парсинге 10 статей, чтобы понять суть.

А вот и сам скрипт — файл index.php

	require 'db.php'; // подключаем библиотеку ReadbeenPHP и соединяемся с базой данных
	require('/phpQuery/phpQuery.php');	// подключаем phpQuery
	define('HOST','http://tbeauty.ru'); // сюда мы вписываем адрес сайта-донора, который необходимо спарсить 

	R::wipe('post'); // удаляем все записи из таблицы post
	R::wipe('postprev'); // удаляем все записи из таблицы postprev

	$data_site = file_get_contents(HOST); // получаем страницу сайта-донора
	$document = phpQuery::newDocument($data_site);
	$content_prev = $document->find('.news .post');

	// перебираем в цикле все посты
	foreach ($content_prev as $el) {
		// Парсим превьюшки статей
    $pq = pq($el); // pq это аналог $ в jQuery
    $h2 = $pq->find('.post-title h2 a')->attr('title'); // парсим заголовок статьи 
    $link = $pq->find('.post-title h2 a')->attr('href'); // парсим ссылку на статью
    $text = $pq->find('.post-content p'); // парсим текст в превью статьи
    $img = $pq->find('.wp-post-image')->attr('src'); // парсим ссылку на изображение в превью статьи

  	// Записываем информацию о превьюшках в базу данных
  	$post_prev = R::dispense('postprev'); 
		if(!empty($h2)) $post_prev->h2 = strip_tags($h2); // strip_tags удаляет HTML тэги из строки
		if(!empty($link)) $post_prev->link = HOST.$link;
		if(!empty($text)) $post_prev->text = strip_tags($text); 
		if(!empty($img)) $post_prev->img = HOST.$img;	 
		R::store($post_prev);

		// пробегаемся по всем ссылкам на посты и парсим контент из открытых статей
		if(!empty($link)) $data_link = file_get_contents(HOST.$link);
		$document_с = phpQuery::newDocument($data_link);
		$content = $document_с->find('.broden-ajax-content');
		
		foreach ($content as $element) {
			$pq2 = pq($element);
			$h1 = $pq2->find('.post-title h1'); // парсим главный заголовок статьи
			$text_all = $pq2->find('.article__content .txt'); // парсим контент часть статьи
  	    }

  	// Записываем информацию о статьях в базу данных
  	$post = R::dispense('post'); 
		if(!empty($h1)) $post->h1 = strip_tags($h1);
		if(!empty($text_all)) $post->text = strip_tags($text_all); 
		R::store($post);

  }

Соединение с БД — файл db.php

require 'libs/rb.php';
R::setup( 'mysql:host=127.0.0.1;dbname=parserlinio','root', '' ); 

if ( !R::testconnection() )
{
		exit ('Нет соединения с базой данных');
}


Если мы запустим парсер, то в базе данных автоматически появятся 2 таблички. В таблице postprev запишется информация о превью статей (картинка, заголовок, небольшой текст и ссылка на сам пост).
В таблицу post запишется уже полная информация о статьях.

Вот такая красота в итоге получается.

Таблица postprev

Таблица postprev

 


Таблица post

Таблица post


Как работает парсер?

  1. Подключаемся к нашей базе данных (файл db.php)
  2. Подключаем библиотеки
  3. Создаем константу, в которой хранится адрес сайта-донора
  4. Очищаем таблицы post и postprev в БД. Это нужно для того, чтобы при повторном запуске парсера, данные в таблицах не дублировались. Момент очень спорный. Возможно, можно было сделать проверку на совпадение с данными в БД и уже потом производить запись или назначать статусы (0 – не парсили, 1 — парсили). Если есть мысли, то пишите в комментариях
  5. Функцией file_get_contents получаем содержимое страницы
  6. Смотрим, как у сайта-донора устроена разметка постовhtml разметка
  7. Перебираем в цикле foreach все посты
  8. Проверяем разметку превью постов и смотрим, в каких тэгах находятся необходимые данные (заголовок, картинка и т.д.)
  9. Информацию о превью, которую мы спарсили записываем в БД. Делается это методом dispense библиотеки RedbeenPHP, который принимает всего 1 аргумент – название таблицы.
    Причем, если такой таблицы в БД нет, то он сам её корректно создаст
  10. В пункте 8 мы спарсили ссылки на посты. Теперь можно перебрать их в цикле, чтобы спарсить текст внутри статей и заголовоки
  11. По аналогии с пунктом 9 записываем информацию о статьях в БД
  12. Теперь вам остается лишь самостоятельно вывести информацию из БД на свой сайт
  13. Также можно настроить CRON на своем сервере, чтобы файл index.php автоматически запускался, например, раз в неделю.
    Делается это в разделе планировщик задач. Также можно попросить помощи у техподдержки хостинга.

P.S. Данный парсер очень простой и его функционал можно расширять до бесконечности.
Тестировался парсер на OpenServer. Версия PHP 5.6. На момент написания статьи всё работало. Если у вас не работает, то возможно у сайта-донора поменялся дизайн и соответственно вёрстка.