Блог Froxy | Новости, полезные статьи о использовании прокси

Как сделать ваш скрипт веб-парсинга легальным: гайд для 2026

Written by Команда Froxy | 01.07.2026 3:00:00

Все разработчики парсеров без исключения рано или поздно задаются вопросом – легален ли парсинг? И главное – как сделать так, чтобы скрипт парсинга работал в строгом соответствии с законом и требованиями целевых сайтов? В этом материале расставляем все точки над «i».

Максимально краткий ответ <TL;DR>

Итак, легальность веб-парсинга, во-первых, определяется его целями. Если вы собираете чужие персональные данные или авторский контент без согласия правообладателей – это нарушение закона в большинстве стран. Где-то парсинг может вообще попасть под статью о промышленном шпионаже.

Большинство юридических рисков возникает не на этапе сбора данных, а уже после – при их дальнейшем хранении, публикации, перепродаже или коммерческом использовании.

Во-вторых, если ваш скрипт парсинга создаёт чрезмерную нагрузку на инфраструктуру провайдера и проводит к ошибкам в работе, а также к недоступности сервиса для «живых» пользователей, то вполне может возникнуть финансовая ответственность – в размере понесённых убытков. Это тоже актуально для многих стран мира.

Вместе с тем, если данные публичные, вы их видите и можете скопировать вручную, например, для исследования или для сводного анализа, то технически парсинг – это лишь автоматизация вашего исследования.

Получается, что легальный веб-парсинг вполне возможен – без каких-либо специальных разрешений и договоров.

Но, чтобы вас не могли привлечь к какой-либо ответственности, следует:

  • Собирать только публично доступные данные.
  • Не использовать чужую интеллектуальную собственность, а особенно – персональные данные.
  • Соблюдать правила и нормы, оговоренные в пользовательском соглашении целевого сайта, а также в специальных директивах для роботов и поисковых систем (robots.txt).
  • Ограничивать частоту запросов, чтобы не создавать избыточную нагрузку на серверы. Для снижения частоты обращений, исключения дублей и повторных проходов также следует подумать о кэшировании и сохранении единой очереди запросов с механизмом очистки.
  • Не использовать собранную информацию для рассылки спама, мошенничества, недобросовестной конкуренции и других противоправных действий.
  • Хранить логи работы парсера и истории запросов – на случай подтверждения добросовестности ваших действий и намерений.

Ниже добавим больше технических деталей.

Автоматическое применение политик: анализ файла robots.txt

Все технические правила для поисковых ботов (куда можно «ходить», а куда нельзя и кому) изложены в файле robots.txt. Официальную документация по правилам и директивам для чтения и понимания robots.txt можно найти на сайте проекта, а также в справочных разделах поисковых систем, например, Google.

Так как ничто не мешает вашему боту представиться любым именем, из robots.txt имеет смысл «читать» только общие директивы и каталоги, которые помечены на исключение из обхода.

Пример обработчика для Python (сами директивы вам нужно будет скопировать и прописать вручную):

# Массив с исключениями / директивы Disallow
disallow_rules = [
    "/admin/",
    "/private/",
    "/search"
]

# Пример целевого запроса парсера
url = "https://example.com/private/data"

# Проверка запроса на наличие исключений
path = urlparse(url).path

# Срабатывание правила блокировки
blocked = any(path.startswith(rule) for rule in disallow_rules)

# Сохранение информации в логи
if blocked:
    logger.warning(
        f"URL skipped by robots.txt policy: {url}"
    )

# Если исключений нет, то просто продолжаем парсинг
else:
    queue.append(url)

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

Резидентные прокси

Прокси для доступа к ценным данным со всего мира.

Получить триал $1.99, 100Mb

Идентификация и прозрачность: настройка пользовательских агентов

При написании любого парсера у разработчика есть два пути:

  • Предоставить фактическое описание своего бота, идентифицировать его и предоставить реальные контактные данные – для получения обратной связи и официальных юридических запросов.
  • Представиться чужим именем и смоделировать такие параметры User-Agent'а, которые гарантированно пройдут системы защиты.

Раз материал о юридических аспектах и легальности веб-парсинга, то мы настоятельно рекомендуем идти по первому пути. Идентификация бота (юзер-агента) осуществляется на уровне специальных HTTP-ответов.

Ниже примеры настройки уникальных цифровых отпечатков для бота.

Вариант для работы через HTTP-клиент Requests:

import requests

headers = {
# В параметрах уникальный идентификатор и контактная информация
    "User-Agent": (
        "ResearchBot/1.4 "
        "(+https://crawler.example.com; "
        "contact: crawler@example.com)"
    ),
# Плюс ряд параметров, которые позволяют «синхронизировать» тип обрабатываемого содержимого и некоторые другие параметры
    "Accept": "text/html,application/xhtml+xml",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
    "From": "crawler@example.com"
}

# Отправка первого запроса с указанными параметрами
response = requests.get(
    "https://example.com", # целевой URL
    headers=headers, # Тут массив заголовков
    timeout=10 # Таймаут
)

Вариант для headless-браузеров

Так как в headless-браузерах уровень сложности цифрового отпечатка выше (принимающий сервер может анализировать не только HTTP-заголовки, но и JavaScript-окружение клиента), то и параметров в заголовках нужно передавать больше.

Базовый профиль для Playwright (Chromium) может выглядеть так:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=True
    )
    context = browser.new_context(
        user_agent=(
            "CrawlerRenderer/2.1 "
            "(Rendering Bot; "
            "+https://crawler.example.com)"
        ),
        locale="en-US",
        extra_http_headers={
            "From": "crawler@example.com",
            "DNT": "1"
        }
    )

    page = context.new_page()
    page.goto("https://example.com")

В расширенном описании отпечатка можно также предусмотреть параметры для:

  • navigator.webdriver;
  • списка браузерных плагинов;
  • WebGL-параметров;
  • Canvas-отпечатка;
  • набора шрифтов;
  • временной зоны и локали;
  • поведения JavaScript-таймеров;
  • DevTools-признаков.

Именно по ним специальные системы защиты определяют работу ботов.

Материал по теме: Цифровой отпечаток браузера (как вас идентифицируют в сети).

Соответствие требованиям инфраструктуры: прокси-уровень

Слой и правила балансировки нагрузки наиболее важны. Если вы обращаетесь к целевому сайту слишком часто, то нагрузка на серверы возрастает кратно. В какой-то момент обычные пользователи могут начать сталкиваться с замедлением сервиса или даже с его полным отказом – тут всё будет зависеть от производительности принимающего сервера и сетевой архитектуры (внутренней маршрутизации и балансировки нагрузки).

Самый зрелый и правильный подход – распланировать нагрузку, которую потенциально может создать ваш бот.

В противном случае легальный парсинг данных легко превращается в нелегальный.

Со стороны скрипта веб-парсинга слой балансировки нагрузки может выглядеть так:

  • Ограничение количества запросов в единицу времени (RPS / Rate Limit).
  • Добавление случайных задержек между запросами (хотя спорно при легальном парсинге, в любом случае задержки должны быть, хотя бы фиксированные).
  • Ограничение числа параллельных потоков и соединений. Подбор лучшего расписания с учётом пиковых нагрузок – с учётом дней недели, а также времени дня, праздников, знаковых событий и т.п.
  • Разделение нагрузки между несколькими IP-адресами и прокси (если позволяет производительность принимающей стороны).
  • Использование очередей запросов и планировщиков задач.
  • Установка увеличенных интервалов ожидания для повторных запросов в случае ошибок или отсутствия коннекта (желательно с экспоненциальным ростом).
  • Кэширование уже полученных страниц и API-ответов (чтобы не отправлять одни и те же запросы заново, создавая ненужную нагрузку).
  • Контроль глубины обхода и количества одновременно открытых страниц.
  • Учёт HTTP-кодов ответа сервера (429, 403, 503) и автоматическое снижение интенсивности парсинга при ошибках.
  • Очистка очереди обхода от дублей и исключение циклического обхода списков (по кругу).
  • Разделение «тяжёлых» и «лёгких» запросов по разным очередям. Тяжёлые запросы традиционно связаны с фильтрами и пагинацией.
  • Автоматическое отключение проблемных прокси и IP-адресов или использование качественных ротируемых прокси, например, мобильных или резидентных. Так вашего бота не будут воспринимать как угрозу после первого же контакта.
  • Распределение запросов по географии и временным зонам. В этом случае можно снять нагрузку с одного конкретного сервера, обслуживающего один регион.

Простейшая реализация задержек с небольшим «шумом» относительно базового времени:

import time
import random

BASE_DELAY = 3

while queue:
    url = queue.pop()
    response = requests.get(url)

    # Базовая задержка + случайный шум
    sleep_time = (
        BASE_DELAY +
        random.uniform(0.5, 2.0)
    )
    time.sleep(sleep_time)

Для многопоточных парсеров особенно важно ограничивать количество одновременных соединений:

from concurrent.futures import ThreadPoolExecutor

MAX_WORKERS = 5

with ThreadPoolExecutor(
    max_workers=MAX_WORKERS
) as executor:
    executor.map(parse_page, urls)

Если сервис отдаёт в ответ ошибку доступа, то логично увеличивать время задержки – с большой вероятностью сервер сейчас перегружен. Пример реализации роста задержки – повтор ошибки при запросе будет кратно увеличивать паузу:

retry_delay = 5

for attempt in range(5):
    try:
        response = requests.get(url)
        if response.status_code == 200:
            break
    except Exception:
        pass

    time.sleep(retry_delay)
    retry_delay *= 2

Для распределения нагрузки часто используется ротация прокси:

import random

proxies = [
    "http://proxy1.example.com:8080",
    "http://proxy2.example.com:8080",
    "http://proxy3.example.com:8080"
]

proxy = random.choice(proxies)

response = requests.get(
    url,
    proxies={
        "http": proxy,
        "https": proxy
    }
)
Глобальное покрытие

5 континентов, без ограничений

Получите доступ к прокси-сети с 200+ локациями и 10+ миллионами IP-адресов.

Изучить цены

Управление «стеной входа»: риски, связанные с сессиями

Сейчас многие сайты и веб-сервисы не работают без авторизации, например, мессенджеры, соцсети и т.п. Соответственно, если принимающий сайт обнаружит автоматические запросы, он не просто может ограничить доступ по IP, но и полностью заблокировать аккаунт, под которым велось подключение.

К механизму сессий можно отнести:

  • cookie;
  • токены или идентификаторы сессий;
  • CSRF-токены;
  • отпечатки браузера;
  • историю предыдущих действий.

При парсинге с авторизацией риски юридической ответственности всегда максимальные.

Если скрипт делается без учёта требований к легальности веб-парсинга, то он может имитировать браузерные отпечатки и куки, автоматически создавать новые и ротировать заранее созданные аккаунты, открывать параллельно большое количество сессий, отправлять запросы «по максимуму» и т.п.

Легальный парсер должен придерживаться следующих принципов:

  • Один аккаунт – одна сессия – один прокси – один сбалансированный поток запросов.
  • Если аккаунт получает ошибку, он становится в очередь на ожидание (с ростом задержки).
  • Никаких агрессивных повторных обращений и больших списков «чужих» учётных записей.

Простейший пример хранения независимой сессии в Python:

import requests

session = requests.Session()
session.headers.update({
    "User-Agent": "ResearchBot/1.0"
})

response = session.get(
    "https://example.com/profile"
)

Пример простейшей блокировки повторных запросов:

if response.status_code == 403:
    logger.warning(
        "Access denied. Session disabled."
    )
    disable_worker()

Минимизация данных, оптимизация производительности и защита конфиденциальности (GDPR/CCPA)

Минимизация сводится к:

  • Подключению и сбору данных по официальному API, если он имеется.
  • Использованию алгоритмов сжатия, если они поддерживаются целевым сайтом.
  • Проверке очереди страниц для обхода на дубли.
  • Очистке URL-адресов от технических параметров, которые приводят к дублированию.
  • Сохранению истории обращений и статуса обхода, кешированию данных (чтобы не возвращаться к одним и тем же страницам повторно).
  • Исключению зацикливания списков URL.
  • Очистке полученных данных на этапе сбора – сохранение только полезной и разрешённой информации (а не всего HTML-кода страницы целиком).
  • Намеренной анонимизации персональных данных. Например, замена ФИО, логинов, номеров телефона или email-адресов на идентификаторы или токены.

Лучший способ снижения юридических рисков – не хранить и не собирать чувствительные данные.

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

Пример. Извечный вопрос: легален ли парсинг email? И да, и нет одновременно, как кот Шредингера. Если вы собираете данные из открытых источников, вас никто останавливать не будет. Но если вы попытаетесь сделать рассылку по собранным email-адресам без разрешения их владельцев или попробуете продать базу таких email, то вполне может наступить юридическая ответственность.

Если парсеру нужны только цены товаров, то нет смысла сохранять всю страницу или профиль продавца. Вот так может выглядеть скрипт парсера с использованием синтаксического анализатора Beautiful Soup:

from bs4 import BeautifulSoup

html = response.text
soup = BeautifulSoup(
    html,
    "html.parser"
)

result = {
# Извлечение идентификатора продукта
    "product_id": soup.select_one(
        ".product"
    )["data-id"],

# Извлечение цены продукта
    "price": soup.select_one(
        ".price"
    ).text.strip()
}

Ниже код для автоматического удаления email и номеров телефонов:

import re

text = response.text

# Удаление email
text = re.sub(
    r'[\w\.-]+@[\w\.-]+',
    '[EMAIL_REMOVED]',
    text
)

# Удаление телефонов
text = re.sub(
    r'\+?\d[\d\s\-\(\)]{7,}\d',
    '[PHONE_REMOVED]',
    text
)

В более зрелых системах парсинга фильтрация чувствительных данных может выноситься в отдельные пайплайны или модули:

  • санитайзер;
  • анонимайзер;
  • DLP-фильтр;
  • менеджер хранения данных.

Материал по теме: Кеширование в Python при скрапинге – сокращение количества запросов и ускорение сбора данных.

Аудит и ведение журналов для правовой защиты

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

Поэтому, чем подробнее и точнее будет система логирования, тем вам же лучше.

Какую информацию имеет смысл выносить в логи:

  • Куда (к каким URL-адресам) обращается скрипт.
  • Когда он обращается (дата + точное время).
  • Какие данные извлекает.
  • Какие данные исключает (например, для обработки правил robots.txt).
  • Успешный запрос или нет.
  • Какой код ошибки получен и какие действия предприняты (например, увеличена задержка для ожидания повторного обращения).
  • Какие параметры авторизации использованы (прокси, аккаунты и т.п.).

Простейший пример логирования запросов и ошибок:

import logging
import requests
import time

logging.basicConfig(
    filename="crawler.log",
    level=logging.INFO,
    format=(
        "%(asctime)s "
        "[%(levelname)s] "
        "%(message)s"
    )
)

url = "https://example.com"

try:
    start = time.time()
    response = requests.get(
        url,
        timeout=10
    )
    duration = round(
        time.time() - start,
        2
    )

    logging.info(
        f"URL={url} "
        f"STATUS={response.status_code} "
        f"TIME={duration}s"
    )

except Exception as e:
    logging.error(
        f"URL={url} "
        f"ERROR={str(e)}"
    )

Заключение

Соблюдение официальных правил и требований целевых сайтов, а также простая человеческая логика и этика всегда должны оставаться в приоритете. Только так можно добиться высоких стандартов качества и максимальной легальности веб-парсинга для своих скриптов.

Если вы ищите качественные прокси для профессиональной работы, с официальным сотрудничеством и удобными расчётами, выбирайте Froxy. Мы работаем абсолютно легально, в правовом поле Европы и предоставляем все необходимые закрывающие документы.