Skip to content
EN
← Все статьи

Python простыми словами и 7 скриптов для проверки сайта

Монитор с кодом скрипта и терминалом, где выводятся результаты проверки сайтов

Python (по-русски говорят «питон» или «пайтон») — язык программирования общего назначения с простым синтаксисом и большой стандартной библиотекой. На нём пишут веб-сервисы, анализ данных и нейросети, а владельцу сайта он полезен короткими скриптами: 15–40 строк проверяют коды ответа страниц, срок SSL-сертификата, DNS-записи и битые ссылки.

Что такое Python простыми словами

Python — это язык, на котором программу читают почти как текст: блоки выделяются отступами, а не фигурными скобками, переменные не нужно объявлять заранее, типы определяются во время работы. Программа на Python не компилируется в отдельный exe-файл: её исполняет интерпретатор — та самая программа python, которую вы устанавливаете с python.org. Написали файл check.py, запустили командой python check.py — получили результат.

Для автоматизации проверок сайта у Python три сильные стороны.

  • Стандартная библиотека. Модули ssl, socket, urllib, json, csv, html.parser идут вместе с интерпретатором. Срок сертификата или разбор HTML-страницы не требуют ничего устанавливать.
  • Каталог пакетов PyPI. Если стандартной библиотеки мало, команда pip install ставит готовое: requests для HTTP, dnspython для DNS-запросов любого типа.
  • Кроссплатформенность. Один и тот же скрипт работает на Windows, macOS и Linux-сервере, где его удобно запускать по расписанию.

Где используют Python

Бэкенд сайтов (Django, Flask, FastAPI), анализ данных и отчёты (pandas), машинное обучение и нейросети (PyTorch, TensorFlow), системное администрирование и DevOps-скрипты, парсинг сайтов, тестирование. Для владельца сайта самое практичное — последний пункт из этого ряда: быстрые проверки, которые иначе делают руками в браузере по одной странице.

Как установить Python и запустить первый скрипт

Windows

Скачайте установщик со страницы python.org/downloads. На первом экране классического установщика поставьте галочку Add python.exe to PATH — без неё команда python в консоли не найдётся. На странице загрузок для Windows может предлагаться и новый менеджер установки Python install manager; с ним команды py и python настраиваются при установке.

Проверка в cmd или PowerShell:

py --version
python --version

Если вместо версии открывается Microsoft Store, сработал системный псевдоним-заглушка. Его отключают в «Параметры → Приложения → Дополнительные параметры приложений → Псевдонимы выполнения приложений» (выключить python.exe и python3.exe) либо просто пользуются командой py.

macOS

Есть два пути: установщик с python.org или Homebrew (brew install python). После установщика с python.org обязательно запустите файл Install Certificates.command из папки «Программы → Python 3.x». Без этого шага модули ssl и urllib падают на любом HTTPS-сайте с ошибкой CERTIFICATE_VERIFY_FAILED ... unable to get local issuer certificate — мы поймали её, пока проверяли скрипты для этой статьи. Библиотека requests при этом работает, потому что носит свой набор корневых сертификатов (пакет certifi).

Linux

В большинстве дистрибутивов Python 3 уже стоит. Не хватает обычно модулей venv и pip:

# Debian, Ubuntu
sudo apt install python3 python3-venv python3-pip
# Fedora, RHEL, AlmaLinux
sudo dnf install python3 python3-pip

Первый скрипт

Создайте файл hello.py в любом редакторе (удобно в VS Code — о нём отдельный разбор):

import sys
print("Python", sys.version)

Запуск: python3 hello.py на macOS и Linux, py hello.py на Windows. Если увидели номер версии — всё готово.

pip и venv: как ставить библиотеки

pip — установщик пакетов из PyPI. venv — виртуальное окружение: папка проекта со своей копией интерпретатора и своими библиотеками. Окружение нужно, чтобы пакеты одного проекта не ломали другие и системный Python. Для скриптов из этой статьи хватит одного окружения:

# macOS и Linux
python3 -m venv .venv
source .venv/bin/activate
pip install requests dnspython

# Windows, cmd
py -m venv .venv
.venv\Scripts\activate.bat
pip install requests dnspython

# Windows, PowerShell
.venv\Scripts\Activate.ps1

Если PowerShell отказывается запускать Activate.ps1 из-за политики выполнения, разрешите локальные скрипты для своей учётной записи: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.

В свежих Debian и Ubuntu команда pip install вне окружения завершается ошибкой error: externally-managed-environment. Это не поломка, а защита системного Python по PEP 668: ставьте пакеты в venv, как выше. Подробности — в документации модуля venv.

Синтаксис Python: что значит в коде ниже

Чтобы читать скрипты из следующего раздела, достаточно знать десяток конструкций. Частые вопросы «что значит в питоне» обычно как раз про них.

ЗаписьЧто значитПример
#Комментарий до конца строки, интерпретатор его пропускает# проверяем SSL
= и ==Присваивание и сравнение на равенствоdays = 30, if code == 200:
!=, >=, <Не равно, больше или равно, меньшеif status >= 400:
// и %Целочисленное деление и остатокseconds // 86400 — целые сутки
f"..."f-строка: подставляет значения выражений в фигурных скобкахf"{host}: {days} дн."
: и отступНачало блока; всё, что сдвинуто на 4 пробела, входит в блокfor url in URLS:
withОткрывает ресурс и гарантированно закрывает его, даже при ошибкеwith socket.create_connection(...) as sock:
try / exceptПерехват ошибок: скрипт не падает, а сообщает, что случилосьexcept requests.RequestException:
[ ], { }Список и словарь (или множество){"q": host}
sys.exit(1)Завершить скрипт с кодом ошибки — его видят cron и планировщикsys.exit(1 if failed else 0)

Python для владельца сайта: 7 скриптов проверки

Все примеры ниже запускались на Python 3.13 с requests 2.34 и dnspython 2.8; нужен Python 3.10 или новее. В каждом есть таймаут и обработка ошибок: без timeout библиотека requests может ждать ответа сервера бесконечно, и зависший скрипт в расписании хуже, чем упавший. Скрипты возвращают код выхода 1, если нашли проблему, — это пригодится для запуска по расписанию. Какие ещё пункты стоит проверять на сайте, собрано в техническом чек-листе проверки сайта на ошибки.

1. Проверить код ответа списка URL

Самая частая задача: у вас список важных страниц — главная, каталог, корзина, форма заявки — и нужно убедиться, что все отвечают 200, а не 404 или 500.

import sys
import requests

URLS = [
    "https://example.com/",
    "https://example.com/no-such-page",
    "https://www.python.org/",
]
HEADERS = {"User-Agent": "site-check/1.0 (+admin@example.com)"}

failed = 0
for url in URLS:
    try:
        r = requests.get(url, headers=HEADERS, timeout=10, allow_redirects=False)
        note = r.headers.get("Location", "")
        print(f"{r.status_code}  {url}  {note}")
        if r.status_code >= 400:
            failed += 1
    except requests.RequestException as e:
        print(f"ERR  {url}  {type(e).__name__}: {e}")
        failed += 1

sys.exit(1 if failed else 0)

Параметр allow_redirects=False здесь намеренный: скрипт показывает код самой страницы, а для 301 и 302 — адрес из заголовка Location. Иначе requests молча пройдёт редирект, и вы увидите 200 конечной страницы. Заголовок User-Agent с контактом нужен потому, что часть сайтов режет запросы со стандартной подписью python-requests. Что означает каждый код, есть в справочнике HTTP-кодов ответа.

2. Узнать срок действия SSL-сертификата

Модули ssl и socket из стандартной библиотеки, ничего ставить не нужно:

import socket
import ssl
import sys
import time

HOSTS = ["example.com", "python.org", "expired.badssl.com"]
WARN_DAYS = 14

def days_left(host, port=443):
    ctx = ssl.create_default_context()
    with socket.create_connection((host, port), timeout=10) as sock:
        with ctx.wrap_socket(sock, server_hostname=host) as tls:
            cert = tls.getpeercert()
    expires = ssl.cert_time_to_seconds(cert["notAfter"])
    return int((expires - time.time()) // 86400), cert["notAfter"]

problems = 0
for host in HOSTS:
    try:
        days, not_after = days_left(host)
        mark = "OK  " if days > WARN_DAYS else "WARN"
        print(f"{mark} {host}: {days} дн. (до {not_after})")
        if days <= WARN_DAYS:
            problems += 1
    except ssl.SSLCertVerificationError as e:
        print(f"FAIL {host}: сертификат не прошёл проверку: {e.verify_message}")
        problems += 1
    except (OSError, ssl.SSLError) as e:
        print(f"ERR  {host}: {type(e).__name__}: {e}")
        problems += 1

sys.exit(1 if problems else 0)

Результат на момент проверки:

OK   example.com: 31 дн. (до Oct 27 22:17:21 2026 GMT)
OK   python.org: 140 дн. (до Feb 14 13:03:45 2027 GMT)
FAIL expired.badssl.com: сертификат не прошёл проверку: certificate has expired

Обратите внимание на третью строку. Контекст ssl.create_default_context() проверяет сертификат при рукопожатии, поэтому просроченный, самоподписанный или выданный на другое имя сертификат даёт не число дней, а исключение SSLCertVerificationError. Для мониторинга это правильное поведение: сайт с таким сертификатом браузер тоже не откроет без предупреждения. Отключать проверку (CERT_NONE) ради числа не нужно — тогда getpeercert() вернёт пустой словарь. Ручные способы проверки сертификата описаны в пошаговом руководстве по SSL.

3. Получить DNS-записи домена

Адреса A и AAAA отдаёт стандартная функция socket.getaddrinfo. Для MX, TXT и NS нужна библиотека dnspython (pip install dnspython, импортируется как dns):

import socket
import sys
import dns.exception
import dns.resolver

DOMAIN = sys.argv[1] if len(sys.argv) > 1 else "example.com"

# A и AAAA — стандартной библиотекой, через системный резолвер
try:
    addrs = {info[4][0] for info in socket.getaddrinfo(DOMAIN, 443, proto=socket.IPPROTO_TCP)}
    print("A/AAAA:", ", ".join(sorted(addrs)))
except socket.gaierror as e:
    print("A/AAAA: не резолвится:", e)

# MX, TXT, NS — через dnspython (pip install dnspython)
resolver = dns.resolver.Resolver()          # берёт DNS-серверы из настроек системы
# resolver.nameservers = ["8.8.8.8"]        # или спросить конкретный публичный резолвер

for rtype in ("MX", "TXT", "NS"):
    try:
        answer = resolver.resolve(DOMAIN, rtype, lifetime=5)
        for rdata in answer:
            print(f"{rtype}: {rdata.to_text()}")
    except dns.resolver.NXDOMAIN:
        print(f"{rtype}: домен не существует")
        break
    except dns.resolver.NoAnswer:
        print(f"{rtype}: записей такого типа нет")
    except dns.exception.DNSException as e:
        print(f"{rtype}: ошибка запроса: {type(e).__name__}")

Запуск: python3 dns_check.py example.com. Разница исключений важна: NXDOMAIN значит, что домена нет вовсе, NoAnswer — домен есть, но записей такого типа у него нет, таймаут — не ответил DNS-сервер. Функция getaddrinfo спрашивает системный резолвер, а значит, учитывает файл hosts и локальный кэш. Если нужен «чистый» ответ из интернета, раскомментируйте строку с nameservers и укажите публичный резолвер. API dnspython описан в официальной документации.

4. Найти битые ссылки на странице

Разбор HTML — встроенным html.parser, проверка ссылок — через requests:

import sys
from html.parser import HTMLParser
from urllib.parse import urljoin, urldefrag, urlparse
import requests

PAGE = sys.argv[1] if len(sys.argv) > 1 else "https://www.python.org/"
HEADERS = {"User-Agent": "site-check/1.0 (+admin@example.com)"}
LIMIT = 100

class LinkParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.links = []

    def handle_starttag(self, tag, attrs):
        if tag == "a":
            href = dict(attrs).get("href")
            if href:
                self.links.append(href)

def check(session, url):
    try:
        r = session.head(url, timeout=10, allow_redirects=True)
        if r.status_code in (403, 405, 501):
            # часть серверов не любит HEAD — переспрашиваем GET без скачивания тела
            r = session.get(url, timeout=10, allow_redirects=True, stream=True)
            r.close()
        return r.status_code
    except requests.RequestException as e:
        return type(e).__name__

with requests.Session() as s:
    s.headers.update(HEADERS)
    page = s.get(PAGE, timeout=15)
    page.raise_for_status()
    parser = LinkParser()
    parser.feed(page.text)

    urls = []
    for href in parser.links:
        absolute = urldefrag(urljoin(page.url, href)).url
        if urlparse(absolute).scheme in ("http", "https") and absolute not in urls:
            urls.append(absolute)

    print(f"Ссылок на странице: {len(urls)}, проверяю первые {min(len(urls), LIMIT)}")
    for url in urls[:LIMIT]:
        status = check(s, url)
        if not isinstance(status, int) or status >= 400:
            print(f"BROKEN {status}  {url}")

Скрипт собирает все <a href>, превращает относительные адреса в абсолютные через urljoin, отбрасывает якоря, mailto: и tel:. Ссылки проверяются запросом HEAD: он не скачивает тело страницы. Учтите, что requests.head() по умолчанию не ходит по редиректам, поэтому allow_redirects=True указан явно. Часть серверов на HEAD отвечает 403 или 405, для них скрипт повторяет запрос через GET.

На странице python.org скрипт нашёл одну «битую» ссылку — BROKEN 999 на LinkedIn. Это не поломка: LinkedIn отвечает нестандартным кодом 999 на запросы, похожие на автоматические. Такие домены удобно держать в списке исключений. Лимит в 100 ссылок и один поток — чтобы не нагружать чужие серверы.

5. Выгрузить title и description страниц в CSV

Для SEO-проверки удобно получить таблицу: адрес, код ответа, title, description и их длину.

import csv
import sys
from html.parser import HTMLParser
import requests

URLS = ["https://example.com/", "https://www.python.org/"]
HEADERS = {"User-Agent": "site-check/1.0 (+admin@example.com)"}

class MetaParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.title = ""
        self.description = ""
        self._in_title = False

    def handle_starttag(self, tag, attrs):
        a = dict(attrs)
        if tag == "title":
            self._in_title = True
        elif tag == "meta" and (a.get("name") or "").lower() == "description":
            self.description = (a.get("content") or "").strip()

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

    def handle_data(self, data):
        if self._in_title:
            self.title += data

writer = csv.writer(sys.stdout)
writer.writerow(["url", "status", "title", "title_len", "description", "desc_len"])
for url in URLS:
    try:
        r = requests.get(url, headers=HEADERS, timeout=15)
        if "charset" not in r.headers.get("Content-Type", "").lower():
            r.encoding = r.apparent_encoding  # иначе cp1251 превратится в кракозябры
        p = MetaParser()
        p.feed(r.text)
        title = " ".join(p.title.split())
        writer.writerow([url, r.status_code, title, len(title), p.description, len(p.description)])
    except requests.RequestException as e:
        writer.writerow([url, type(e).__name__, "", 0, "", 0])

Запуск с сохранением в файл: python3 meta_export.py > meta.csv. Файл открывается в Excel или Google Таблицах. Строка с apparent_encoding нужна для старых сайтов в кодировке windows-1251: если сервер не указал charset в заголовке Content-Type, requests считает страницу ISO-8859-1, и кириллица превращается в набор символов вроде «Ð¡Ñ‚». Пустой description в отчёте (как у example.com) — повод его написать.

6. Проверить цепочку редиректов

После переезда на HTTPS или смены структуры URL нужно убедиться, что старые адреса ведут на новые одним шагом и без петель:

import sys
import requests

URL = sys.argv[1] if len(sys.argv) > 1 else "http://python.org"

try:
    r = requests.get(URL, timeout=10, allow_redirects=True)
except requests.TooManyRedirects:
    sys.exit(f"{URL}: слишком много редиректов — похоже на петлю")
except requests.RequestException as e:
    sys.exit(f"{URL}: {type(e).__name__}: {e}")

for step, hop in enumerate(r.history, 1):
    print(f"{step}. {hop.status_code}  {hop.url}  ->  {hop.headers.get('Location')}")
print(f"Итог: {r.status_code}  {r.url}  (переходов: {len(r.history)})")
$ python3 redirects.py http://python.org
1. 301  http://python.org/  ->  https://www.python.org/
Итог: 200  https://www.python.org/  (переходов: 1)

Атрибут r.history хранит все промежуточные ответы по порядку. Петлю редиректов requests обрывает исключением TooManyRedirects — по умолчанию после 30 переходов. Какие цепочки считаются нормальными и чем плох 302 вместо 301, разобрано в статье о проверке редиректов сайта.

7. Как работать с API в Python: открытый API enterno

Когда проверять надо со стороннего сервера, а не со своего компьютера, можно обратиться к открытому API enterno.io. Для него не нужен ключ: запрос GET https://enterno.io/api/open/ssl?q=example.com возвращает данные о сертификате. Параметр q — проверяемый хост, format — формат ответа: text, json или csv. Для скрипта удобнее JSON, поэтому указываем его явно:

import sys
import requests

API = "https://enterno.io/api/open/ssl"

def ssl_days(host):
    r = requests.get(API, params={"q": host, "format": "json"}, timeout=30)
    data = r.json()
    if "error" in data:
        raise RuntimeError(data["error"])
    print("Осталось запросов:", r.headers.get("X-RateLimit-Remaining"))
    return data["certificate"]["days_left"]

host = sys.argv[1] if len(sys.argv) > 1 else "example.com"
try:
    print(host, ssl_days(host), "дн.")
except (requests.RequestException, ValueError, KeyError, RuntimeError) as e:
    sys.exit(f"{host}: {type(e).__name__}: {e}")
$ python3 enterno_ssl.py example.com
Осталось запросов: 29
example.com 31 дн.

Лимит запросов считается на IP-адрес, остаток сервер возвращает в заголовке X-RateLimit-Remaining. При ошибке API отвечает JSON с полем error — например, «Не удалось определить IP хоста» для несуществующего имени, и скрипт это показывает. Текстовый формат удобен прямо в консоли: curl "https://enterno.io/api/open/ssl?q=example.com" | grep days_left. Для регулярных и объёмных проверок есть API с ключом — /api/v4; оба варианта описаны в документации API.

Какой способ проверки выбрать: сравнение

ЗадачаМодулиНужен pipТипичная ловушка
Коды ответа списка URLrequestsдаБез timeout скрипт может зависнуть; без allow_redirects=False не видно 301
То же без установки пакетовurllib.requestнетКоды 4xx и 5xx приходят исключением HTTPError, а не ответом
Срок SSL-сертификатаssl, socketнетНа macOS после установщика python.org — запустить Install Certificates.command
A и AAAAsocket.getaddrinfoнетУчитывает hosts и локальный кэш
MX, TXT, NSdnspythonдаПутать NXDOMAIN (нет домена) и NoAnswer (нет записи)
Битые ссылкиrequests, html.parserдаHEAD запрещён на части серверов; нестандартные коды вроде 999
Title и descriptionrequests, html.parser, csvдаКодировка windows-1251 без charset в заголовке
Цепочка редиректовrequestsдаПетля обрывается исключением, его надо ловить
Проверка со стороннего сервераrequests + открытый API enternoдаЛимит на IP; по умолчанию ответ текстом, для JSON — format=json

Как запускать проверки по расписанию

Проверка полезна, когда выполняется сама. На Linux-сервере добавьте строку в crontab (crontab -e). Указывайте Python из виртуального окружения напрямую — активировать его в cron не нужно:

0 9 * * * /home/user/checks/.venv/bin/python /home/user/checks/ssl_expiry.py >> /home/user/checks/ssl.log 2>&1

На Windows то же делает «Планировщик заданий»: действие «Запуск программы», программа — C:\checks\.venv\Scripts\python.exe, аргумент — путь к скрипту. Коды выхода 0 и 1 из примеров позволяют настроить реакцию: например, в cron цепочкой || команда-оповещения отправлять сообщение только при проблеме. Помните, что скрипт на вашем компьютере проверяет сайт из вашей сети: если упал провайдер или компьютер выключен, проверка молчит.

Как проверить без кода

Если скрипт выдал странный результат, сверьтесь с независимой проверкой со стороны:

Частые вопросы

Python и питон — это одно и то же?

Да. Python — официальное название, «питон» и «пайтон» — разговорные варианты произношения. Назван язык в честь британского комик-шоу «Летающий цирк Монти Пайтона», а не змеи.

Нужно ли учить Python, чтобы пользоваться этими скриптами?

Нет. Достаточно установить интерпретатор, создать окружение, поставить пакеты и заменить список адресов в начале скрипта на свои. Таблица синтаксиса выше помогает понять, что делает каждая строка.

Чем requests отличается от urllib?

urllib входит в стандартную библиотеку и работает без установки, но код с ним длиннее, а ответы 4xx и 5xx приходят исключением. requests нужно ставить через pip, зато он проще: сессии, история редиректов, удобная работа с JSON.

Почему скрипт на macOS пишет CERTIFICATE_VERIFY_FAILED?

Python с python.org на macOS не подключает системное хранилище сертификатов. Запустите Install Certificates.command из папки «Программы → Python 3.x» или используйте requests, у которого свой набор сертификатов.

Можно ли так проверять чужие сайты?

Одиночные запросы к публичным страницам — да. Не запускайте сотни параллельных запросов к одному серверу: это похоже на атаку и может закончиться блокировкой вашего IP. Уважайте robots.txt и условия использования сайта при сборе данных.

Проверьте ваш сайт прямо сейчас

Проверить свой домен →
Другие статьи: Инструменты
Инструменты
Массовая проверка URL: автоматизация мониторинга сайтов
11.03.2026 · 688 просм.
Инструменты
Как дать Claude и Cursor инструменты диагностики сайта
15.06.2026 · 615 просм.
Инструменты
Что такое MCP-сервер и зачем он нужен
15.06.2026 · 430 просм.
Инструменты
Конструкторы сайтов 2026: рейтинг и как потом переехать
21.07.2026 · 226 просм.