Python-скрипты для SEO и обработки данных: пример проверки метаданных

Python-скрипты для SEO и обработки данных: пример проверки метаданных

Обновлено 2 сентября 2026 года.

Python помогает автоматизировать повторяющиеся проверки: собрать метаданные страниц, объединить выгрузки, найти дубликаты или преобразовать изображения. Польза скрипта определяется корректностью результата на ваших данных. Ответ ИИ с кодом и описание функции ещё не подтверждают, что программа работает.

Подборка впервые опубликована в 2023 году. Прежние сравнения GPT-4 с другими инструментами не сопровождались воспроизводимой методикой, а обещание о проверке и бесплатности всех внешних скриптов нельзя считать актуальной гарантией. Вместо него ниже приведён самостоятельный пример с исходным кодом и понятной областью применения.

Что делает скрипт

Программа последовательно читает список HTTP/HTTPS-адресов из urls.txt, загружает HTML и сохраняет result.csv. В отчёте будут исходный адрес, конечный статус и URL после перенаправлений, title, description, canonical и ошибка, если запрос не удался.

Внешние библиотеки не нужны: используются urllib.request, HTMLParser и csv из стандартной библиотеки Python. Это проверка HTML-ответа сервера; JavaScript не выполняется.

Запуск

  1. Создайте отдельную рабочую папку. Сохраните приведённый код как metadata_audit.py.
  2. Рядом создайте urls.txt в UTF-8: один полный URL в строке. Начните с нескольких страниц своего сайта.
  3. Откройте терминал в этой папке и выполните python metadata_audit.py.
  4. Импортируйте result.csv в табличный редактор, используя UTF-8 и запятую как разделитель. URL и текстовые поля задайте как текст.
import csv
from html.parser import HTMLParser
from pathlib import Path
from urllib.error import HTTPError
from urllib.parse import urljoin, urlsplit
from urllib.request import Request, urlopen

class Metadata(HTMLParser):
    def __init__(self):
        super().__init__()
        self.in_title = False
        self.title = []
        self.description = ""
        self.canonical = ""

    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        if tag == "title":
            self.in_title = True
        if tag == "meta" and (attrs.get("name") or "").lower() == "description":
            self.description = attrs.get("content") or ""
        if tag == "link" and "canonical" in (attrs.get("rel") or "").lower().split():
            self.canonical = attrs.get("href") or ""

    def handle_endtag(self, tag):
        if tag == "title":
            self.in_title = False

    def handle_data(self, data):
        if self.in_title:
            self.title.append(data)

def inspect(url):
    row = dict.fromkeys(["url", "status", "final_url", "title", "description", "canonical", "error"], "")
    row["url"] = url
    try:
        if urlsplit(url).scheme not in ("http", "https"):
            raise ValueError("Expected an HTTP or HTTPS URL")
        request = Request(url, headers={"User-Agent": "MetadataAudit/1.0"})
        with urlopen(request, timeout=20) as response:
            row.update(status=response.status, final_url=response.url)
            if response.headers.get_content_type() != "text/html":
                raise ValueError("Response is not text/html")
            raw = response.read(2_000_001)
            if len(raw) > 2_000_000:
                raise ValueError("HTML exceeds 2 MB")
            charset = response.headers.get_content_charset() or "utf-8"
            parser = Metadata()
            parser.feed(raw.decode(charset))
            row.update(title="".join(parser.title).strip(),
                       description=parser.description,
                       canonical=urljoin(response.url, parser.canonical) if parser.canonical else "")
    except HTTPError as error:
        row.update(status=error.code, final_url=error.url, error=str(error))
        error.close()
    except Exception as error:
        row["error"] = f"{type(error).__name__}: {error}"
    return row

if __name__ == "__main__":
    urls = list(dict.fromkeys(line.strip() for line in Path("urls.txt").read_text(encoding="utf-8-sig").splitlines() if line.strip()))
    fields = ["url", "status", "final_url", "title", "description", "canonical", "error"]
    # Exclusive creation protects an earlier report from overwriting.
    with open("result.csv", "x", encoding="utf-8-sig", newline="") as output:
        writer = csv.DictWriter(output, fieldnames=fields)
        writer.writeheader()
        for url in urls:
            writer.writerow(inspect(url))

Как читать результат

Статус 200 означает успешный HTTP-ответ, но не доказывает индексацию, правильный canonical или отсутствие мягкой ошибки 404. Пустой description означает, что соответствующий тег не найден в разобранном HTML. Если его добавляет JavaScript, результат браузерного просмотра может отличаться.

Читай также:  FTP Bridge 2.1.0: возможности и ограничения опубликованного кода

Сравните исходный и конечный URL: скрипт следует перенаправлениям, но не записывает все промежуточные ответы. Относительный canonical преобразуется в абсолютный относительно конечного URL; HTML-тег base в этом небольшом примере не учитывается. Если canonical повторяется, сохраняется последнее найденное значение, поэтому отдельная проверка дублей тегов всё ещё нужна.

Лимит ответа — 2 МБ, тайм-аут сетевой операции — 20 секунд. Кодировка берётся из HTTP-заголовка, при её отсутствии используется UTF-8. Старые страницы с другой кодировкой могут потребовать доработки. Новый отчёт создаётся в режиме, запрещающем перезапись: для повторного запуска переместите предыдущий result.csv или задайте другое имя.

При редакционной проверке этот код прошёл сценарии перенаправления, кириллицы, HTML-сущностей, относительного canonical и ответа 404; также проверена публичная страница блога BI Data. Это не гарантирует обработку любого сайта: перед большим списком сопоставьте несколько результатов с исходным HTML.

Другие полезные задачи для Python

  • Объединение CSV: сначала сверить состав столбцов, кодировки и типы; после объединения проверить строки и суммы.
  • Поиск дублей: определить бизнес-ключ, чтобы не удалить разные позиции одного заказа.
  • Группировка запросов: вручную проверить кластеры, особенно запросы с разным намерением и похожими словами.
  • Преобразование изображений: сравнить размеры файлов и визуальное качество на типичных изображениях.
  • Обработка текста: сохранять результат отдельно и просматривать изменения до замены исходников.

Для каждого скрипта полезны небольшой входной пример, ожидаемый результат, список зависимостей и журнал ошибок. Это позволяет проверить программу независимо от того, написана она человеком или с помощью ИИ.