Парсер сайта на 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, а не через браузер: так нет ограничения на время выполнения.
  • Благодаря уникальному ключу скрипт можно перезапускать с любого места — уже сохранённые записи пропустятся.
  • Для ежедневного обновления достаточно обходить несколько последних страниц.

Все статьи

Расскажите о задаче — подберём платформу и оценим работу

Обсудить проект