Парсер сайта на PHP: загрузка страниц и сохранение в базу
Как написать простой парсер на PHP: загрузить страницы, разобрать HTML через DOMDocument, сохранить данные в MySQL без дублей и продолжить с места остановки.
Актуальность. Первая версия статьи разбирала парсер цитат bash.im на функциях mysql_* и регулярных выражениях. Функции mysql_* удалены в PHP 7, а вёрстка того сайта давно другая. Принцип тот же, код ниже — на PDO и DOMDocument; адрес и селекторы подставьте под свой источник.
Прежде чем парсить
Проверьте правила сайта-источника и файл robots.txt, не нагружайте сервер частыми запросами и не публикуйте чужие тексты без разрешения. Если у сайта есть API — используйте его.
1. Таблица для данных
CREATE TABLE IF NOT EXISTS quotes (
id INT AUTO_INCREMENT PRIMARY KEY,
source_id INT NOT NULL UNIQUE,
text MEDIUMTEXT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Уникальный ключ на source_id (номер записи на сайте-источнике) не даст сохранить одну запись дважды.
2. Подключение к базе
$pdo = new PDO('mysql:host=localhost;dbname=parser;charset=utf8mb4', 'user', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$insert = $pdo->prepare('INSERT IGNORE INTO quotes (source_id, text) VALUES (?, ?)');
Подготовленный запрос защищает от SQL-инъекций, а INSERT IGNORE молча пропускает уже сохранённые записи.
3. Загрузка и разбор страницы
function parsePage(string $url): array
{
$html = file_get_contents($url);
if ($html === false) {
return [];
}
$dom = new DOMDocument();
libxml_use_internal_errors(true); // реальный HTML редко бывает валидным
$dom->loadHTML('<?xml encoding="utf-8"?>' . $html);
$xpath = new DOMXPath($dom);
$items = [];
foreach ($xpath->query('//article[contains(@class, "quote")]') as $node) {
$id = (int)$xpath->evaluate('string(.//*[@class="quote__id"])', $node);
$text = trim($xpath->evaluate('string(.//*[@class="quote__body"])', $node));
if ($id && $text !== '') {
$items[] = [$id, $text];
}
}
return $items;
}
XPath-выражения в примере условные — посмотрите классы нужных элементов в коде страницы источника. DOMDocument надёжнее регулярных выражений: он не ломается от лишнего пробела или переноса строки в разметке.
4. Обход страниц с паузой
$last = 100; // сколько страниц обойти
for ($page = 1; $page <= $last; $page++) {
foreach (parsePage("https://example.com/page/$page") as [$id, $text]) {
$insert->execute([$id, $text]);
}
sleep(2); // не перегружаем сайт-источник
}
5. Долгий парсинг
- Запускайте скрипт из консоли (
php parser.php) или по cron, а не через браузер: так нет ограничения на время выполнения. - Благодаря уникальному ключу скрипт можно перезапускать с любого места — уже сохранённые записи пропустятся.
- Для ежедневного обновления достаточно обходить несколько последних страниц.