Настройка защиты контента от парсинга 1С-Битрикс
Конкуренты парсят каталог: собирают цены, описания, характеристики, используют для мониторинга или копируют на собственный сайт. Полная защита невозможна — если человек может видеть данные, программа тоже может. Задача — сделать парсинг достаточно дорогим, чтобы он потерял экономический смысл.
Эшелонированная защита
Защита строится в несколько слоёв. Каждый слой ловит разный тип парсеров.
Слой 1 — nginx rate limiting. Первый рубеж, не нагружает PHP:
# /etc/nginx/conf.d/rate-limit.conf
# Зона для ограничения по IP
limit_req_zone $binary_remote_addr zone=catalog:10m rate=20r/m;
limit_req_zone $binary_remote_addr zone=search:10m rate=5r/m;
# Применяем к страницам каталога
location /catalog/ {
limit_req zone=catalog burst=40 nodelay;
limit_req_status 429;
# ... остальные директивы
}
location /search/ {
limit_req zone=search burst=10 nodelay;
limit_req_status 429;
}
Слой 2 — анализ User-Agent. В Битрикс через init.php:
// /local/php_interface/init.php
$blockedAgents = [
'python-requests', 'scrapy', 'curl/', 'wget/',
'Go-http-client', 'Java/', 'PhantomJS', 'Headless',
];
$ua = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
foreach ($blockedAgents as $bad) {
if (str_contains($ua, strtolower($bad))) {
header('HTTP/1.1 403 Forbidden');
exit;
}
}
Примитивные парсеры отваливаются сразу. Продвинутые подменяют User-Agent — используем следующие слои.
Слой 3 — поведенческий анализ. Реальные пользователи не запрашивают 200 страниц каталога за 5 минут. Счётчик запросов по IP в Redis:
namespace Local\Security;
class RateLimiter
{
private const WINDOW = 300; // 5 минут
private const LIMIT = 100; // запросов на каталог
private const BAN_TIME = 3600; // бан на час
public static function check(string $ip): bool
{
$redis = \Bitrix\Main\Data\Cache::createInstance();
// Упрощённо: используем кеш Битрикс
$key = 'ratelimit_catalog_' . md5($ip);
$count = (int)(\Bitrix\Main\Application::getInstance()
->getManagedCache()->get($key) ?? 0);
if ($count > self::LIMIT) {
// Логируем и блокируем
self::banIp($ip);
return false;
}
\Bitrix\Main\Application::getInstance()->getManagedCache()->set(
$key,
$count + 1,
self::WINDOW
);
return true;
}
private static function banIp(string $ip): void
{
// Добавляем в таблицу банов Битрикс (b_stop_list)
\CStopList::Add([
'SITE_ID' => SITE_ID,
'IP_ADDR' => $ip,
'ACTIVE' => 'Y',
'REASON' => 'Автоматический бан: подозрение на парсинг',
]);
}
}
Слой 4 — CAPTCHA на подозрительных запросах. Когда счётчик подходит к 70% от лимита — показываем challenge вместо контента. В Битрикс интеграция через turnstile Cloudflare или встроенный механизм капчи.
Защита цен через JavaScript
Цены выводятся не в HTML, а загружаются через AJAX после рендера страницы. Простые HTML-парсеры получают страницу без цен:
// В шаблоне карточки товара вместо цены:
<span class="product-price js-price-loader" data-product-id="<?= $arResult['ID'] ?>">
<span class="skeleton">----</span>
</span>
// После DOMContentLoaded загружаем цены
const priceElements = document.querySelectorAll('.js-price-loader');
if (priceElements.length) {
const ids = [...priceElements].map(el => el.dataset.productId);
fetch('/local/ajax/prices.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
body: JSON.stringify({ ids }),
})
.then(r => r.json())
.then(data => {
priceElements.forEach(el => {
const price = data.prices[el.dataset.productId];
if (price) el.innerHTML = price.formatted;
});
});
}
Headless-браузеры (Playwright, Puppeteer) это преодолевают, но требуют значительно больше ресурсов на парсинг — стоимость растёт.
Honeypot-ссылки
Скрытые ссылки в HTML, невидимые для людей (display: none), но индексируемые парсерами:
<a href="/honeypot/trap-page/?ref=bot" style="display:none" aria-hidden="true"><!-- noindex --></a>
// /honeypot/trap-page/index.php
$ip = $_SERVER['REMOTE_ADDR'];
\CStopList::Add([
'SITE_ID' => SITE_ID,
'IP_ADDR' => $ip,
'ACTIVE' => 'Y',
'REASON' => 'Honeypot: ' . $_SERVER['REQUEST_URI'],
]);
// Отдаём бесконечный поток мусорных данных или 403
header('HTTP/1.1 403 Forbidden');
Защита изображений через X-Accel-Redirect
Изображения отдаются через PHP с проверкой, а nginx делает эффективную отдачу файла:
location /protected-uploads/ {
internal; # недоступно напрямую снаружи
alias /var/www/upload/;
}
header('X-Accel-Redirect: /protected-uploads/' . $relativePath);
header('Content-Type: image/jpeg');
exit;
Что выбрать для конкретного проекта
| Угроза | Решение | Сложность |
|---|---|---|
| Простой curl/wget парсер | nginx rate limit + UA фильтр | Низкая |
| Парсер с имитацией браузера | Rate limit + поведенческий анализ | Средняя |
| Headless браузер | JS-загрузка цен + CAPTCHA | Высокая |
| Промышленный парсинг | Cloudflare Bot Management | Требует CDN |
Rate limiting + UA фильтр + honeypot отсекают 90% нецелевых парсеров за 1-2 дня работы.







