Полное руководство по маскировке Selenium и Puppeteer от детекции
Современные системы антибот-защиты легко распознают автоматизированные браузеры по десяткам признаков: от переменных JavaScript до особенностей поведения WebDriver. Сайты используют Cloudflare, DataDome, PerimeterX и собственные решения, которые блокируют до 90% запросов от Selenium и Puppeteer в стандартной конфигурации.
В этом руководстве разберём все методы маскировки автоматизации: от базовых настроек до продвинутых техник обхода детекции. Вы получите готовые решения с примерами кода для Python и Node.js, которые работают против большинства защитных систем.
Как сайты обнаруживают автоматизацию
Системы антибот-защиты анализируют браузер по множеству параметров одновременно. Даже если вы скроете один признак, остальные выдадут автоматизацию. Понимание всех методов детекции — ключ к эффективной маскировке.
WebDriver-индикаторы
Самый простой метод обнаружения — проверка JavaScript-переменных, которые присутствуют только в автоматизированных браузерах:
// Эти переменные выдают Selenium/Puppeteer
navigator.webdriver === true
window.navigator.webdriver === true
document.$cdc_ // ChromeDriver специфичная переменная
window.document.documentElement.getAttribute("webdriver")
navigator.plugins.length === 0 // У автоматизированных браузеров нет плагинов
navigator.languages === "" // Пустой список языков
Cloudflare и подобные системы проверяют эти свойства в первую очередь. Если хотя бы одно возвращает положительный результат — запрос блокируется.
Фингерпринтинг браузера
Продвинутые системы создают уникальный отпечаток браузера на основе десятков параметров:
- Canvas Fingerprinting — рендеринг скрытых изображений и анализ пиксельных данных
- WebGL Fingerprinting — параметры графического рендерера и видеокарты
- Audio Context — уникальные характеристики аудио-обработки
- Fonts Fingerprinting — список установленных шрифтов в системе
- Screen Resolution — разрешение экрана, глубина цвета, доступная область
- Timezone & Language — часовой пояс, языки браузера, локаль системы
Автоматизированные браузеры часто имеют нетипичные комбинации этих параметров. Например, Headless Chrome не имеет плагинов, но поддерживает WebGL — такая комбинация встречается крайне редко у реальных пользователей.
Поведенческий анализ
Современные системы отслеживают паттерны поведения:
- Движения мыши — боты двигают курсор по прямым линиям или не двигают вообще
- Скорость действий — мгновенное заполнение форм, нечеловеческая скорость кликов
- Паттерны скроллинга — резкие прыжки вместо плавной прокрутки
- События клавиатуры — отсутствие естественных задержек между нажатиями
- Частота запросов — слишком регулярные интервалы между действиями
Важно: DataDome и PerimeterX используют машинное обучение для анализа поведения. Они обучены на миллионах сессий и могут распознать бота даже при правильной маскировке технических параметров, если поведение выглядит неестественно.
Базовая маскировка Selenium
Selenium WebDriver в стандартной конфигурации оставляет множество следов. Рассмотрим пошаговую настройку для минимизации детекции на примере Python и ChromeDriver.
Отключение флага webdriver
Первый шаг — скрыть переменную navigator.webdriver. Это делается через Chrome DevTools Protocol:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
# Настройка опций Chrome
chrome_options = Options()
# Отключаем флаг автоматизации
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# Создаём драйвер
driver = webdriver.Chrome(options=chrome_options)
# Удаляем webdriver через CDP
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
'''
})
driver.get('https://example.com')
Настройка User-Agent и других заголовков
Headless-браузеры часто используют устаревшие или специфичные User-Agent строки. Необходимо установить актуальный User-Agent реального браузера:
# Актуальный User-Agent Chrome на Windows
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
chrome_options.add_argument(f'user-agent={user_agent}')
# Дополнительные аргументы для маскировки
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-gpu')
# Размер окна как у реального пользователя
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--start-maximized')
Добавление плагинов и языков
Автоматизированные браузеры не имеют плагинов и часто показывают пустой список языков. Исправляем это через CDP:
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en', 'ru']
});
Object.defineProperty(navigator, 'plugins', {
get: () => [
{
0: {type: "application/x-google-chrome-pdf", suffixes: "pdf", description: "Portable Document Format"},
description: "Portable Document Format",
filename: "internal-pdf-viewer",
length: 1,
name: "Chrome PDF Plugin"
},
{
0: {type: "application/pdf", suffixes: "pdf", description: ""},
description: "",
filename: "mhjfbmdgcfjbbpaeojofohoefgiehjai",
length: 1,
name: "Chrome PDF Viewer"
}
]
});
Object.defineProperty(navigator, 'platform', {
get: () => 'Win32'
});
'''
})
Полный пример настройки Selenium
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import random
def create_stealth_driver():
chrome_options = Options()
# Базовые настройки маскировки
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
# User-Agent
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
chrome_options.add_argument(f'user-agent={user_agent}')
# Размер окна
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--start-maximized')
driver = webdriver.Chrome(options=chrome_options)
# Скрипт маскировки через CDP
stealth_script = '''
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']});
Object.defineProperty(navigator, 'platform', {get: () => 'Win32'});
window.chrome = {
runtime: {}
};
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5]
});
'''
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': stealth_script
})
return driver
# Использование
driver = create_stealth_driver()
driver.get('https://bot.sannysoft.com/') # Сайт для проверки детекции
Настройка Puppeteer для обхода детекции
Puppeteer имеет те же проблемы с детекцией, что и Selenium. Однако для Node.js существует готовая библиотека puppeteer-extra-plugin-stealth, которая автоматизирует большинство настроек маскировки.
Установка puppeteer-extra
npm install puppeteer puppeteer-extra puppeteer-extra-plugin-stealth
Базовая конфигурация с плагином stealth
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
// Подключаем плагин маскировки
puppeteer.use(StealthPlugin());
(async () => {
const browser = await puppeteer.launch({
headless: 'new', // Новый headless режим Chrome
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920,1080',
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process'
]
});
const page = await browser.newPage();
// Устанавливаем viewport
await page.setViewport({
width: 1920,
height: 1080,
deviceScaleFactor: 1
});
// Устанавливаем User-Agent
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
// Дополнительные заголовки
await page.setExtraHTTPHeaders({
'Accept-Language': 'en-US,en;q=0.9',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
});
await page.goto('https://bot.sannysoft.com/');
// Скриншот для проверки
await page.screenshot({ path: 'test.png' });
await browser.close();
})();
Ручная настройка без плагинов
Если вы хотите полный контроль или не можете использовать сторонние библиотеки, настройте маскировку вручную:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
// Переопределяем webdriver и другие свойства
await page.evaluateOnNewDocument(() => {
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en']
});
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5]
});
// Маскируем Chrome headless
Object.defineProperty(navigator, 'platform', {
get: () => 'Win32'
});
window.chrome = {
runtime: {}
};
// Переопределяем permissions
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
});
await page.goto('https://example.com');
await browser.close();
})();
Настройка для обхода Cloudflare
Cloudflare использует продвинутые методы детекции. Для обхода необходимо добавить случайные задержки и эмуляцию действий:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
async function bypassCloudflare(url) {
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-web-security'
]
});
const page = await browser.newPage();
// Случайный User-Agent
const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
];
await page.setUserAgent(userAgents[Math.floor(Math.random() * userAgents.length)]);
// Переход на страницу
await page.goto(url, { waitUntil: 'networkidle2' });
// Ждём проверку Cloudflare (обычно 5-10 секунд)
await page.waitForTimeout(8000);
// Случайное движение мыши
await page.mouse.move(100, 100);
await page.mouse.move(200, 200);
const content = await page.content();
await browser.close();
return content;
}
Борьба с JavaScript-фингерпринтингом
JavaScript-фингерпринтинг — это создание уникального отпечатка браузера на основе множества параметров. Даже если вы скрыли webdriver, системы анализируют сотни других свойств для выявления автоматизации.
Основные векторы фингерпринтинга
Системы антибот-защиты проверяют следующие параметры:
| Параметр | Что проверяется | Риск детекции |
|---|---|---|
| navigator.webdriver | Наличие флага автоматизации | Критический |
| navigator.plugins | Количество и типы плагинов | Высокий |
| window.chrome | Наличие Chrome API | Средний |
| navigator.permissions | API разрешений браузера | Средний |
| screen.colorDepth | Глубина цвета экрана | Низкий |
| navigator.hardwareConcurrency | Количество ядер процессора | Низкий |
Комплексный скрипт маскировки
Скрипт ниже переопределяет большинство проблемных свойств. Внедряйте его через CDP (Selenium) или evaluateOnNewDocument (Puppeteer):
const stealthScript = `
// Удаляем webdriver
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
// Добавляем chrome объект
window.chrome = {
runtime: {},
loadTimes: function() {},
csi: function() {},
app: {}
};
// Переопределяем permissions
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
// Маскируем плагины
Object.defineProperty(navigator, 'plugins', {
get: () => {
return [
{
0: {type: "application/x-google-chrome-pdf", suffixes: "pdf"},
description: "Portable Document Format",
filename: "internal-pdf-viewer",
length: 1,
name: "Chrome PDF Plugin"
},
{
0: {type: "application/pdf", suffixes: "pdf"},
description: "Portable Document Format",
filename: "internal-pdf-viewer",
length: 1,
name: "Chrome PDF Viewer"
},
{
0: {type: "application/x-nacl"},
description: "Native Client Executable",
filename: "internal-nacl-plugin",
length: 2,
name: "Native Client"
}
];
}
});
// Языки
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en']
});
// Platform
Object.defineProperty(navigator, 'platform', {
get: () => 'Win32'
});
// Vendor
Object.defineProperty(navigator, 'vendor', {
get: () => 'Google Inc.'
});
// Удаляем следы Selenium
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array;
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise;
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol;
// Battery API (отсутствует в headless)
if (!navigator.getBattery) {
navigator.getBattery = () => Promise.resolve({
charging: true,
chargingTime: 0,
dischargingTime: Infinity,
level: 1
});
}
`;
Удаление WebDriver-свойств
ChromeDriver и другие WebDriver-реализации добавляют специфичные переменные в глобальную область видимости. Эти переменные начинаются с префикса cdc_ и легко обнаруживаются защитными системами.
Обнаружение cdc-переменных
Проверить наличие этих переменных можно простым скриптом:
// Поиск всех cdc-переменных
for (let key in window) {
if (key.includes('cdc_')) {
console.log('Обнаружена переменная WebDriver:', key);
}
}
// Типичные переменные ChromeDriver:
// cdc_adoQpoasnfa76pfcZLmcfl_Array
// cdc_adoQpoasnfa76pfcZLmcfl_Promise
// cdc_adoQpoasnfa76pfcZLmcfl_Symbol
// $cdc_asdjflasutopfhvcZLmcfl_
Метод 1: Удаление через CDP
Самый надёжный способ — удалить переменные до загрузки страницы через Chrome DevTools Protocol:
from selenium import webdriver
driver = webdriver.Chrome()
# Удаляем все cdc-переменные
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': '''
// Удаляем известные cdc-переменные
const cdcProps = [
'cdc_adoQpoasnfa76pfcZLmcfl_Array',
'cdc_adoQpoasnfa76pfcZLmcfl_Promise',
'cdc_adoQpoasnfa76pfcZLmcfl_Symbol',
'$cdc_asdjflasutopfhvcZLmcfl_'
];
cdcProps.forEach(prop => {
delete window[prop];
});
// Удаляем все переменные содержащие 'cdc_'
Object.keys(window).forEach(key => {
if (key.includes('cdc_') || key.includes('$cdc_')) {
delete window[key];
}
});
'''
})
Метод 2: Модификация ChromeDriver
Более радикальный подход — изменить бинарный файл ChromeDriver, заменив строку cdc_ на другую последовательность символов. Это предотвращает создание этих переменных:
import re
def patch_chromedriver(driver_path):
"""
Патчит ChromeDriver, заменяя 'cdc_' на случайную строку
"""
with open(driver_path, 'rb') as f:
content = f.read()
# Заменяем все вхождения 'cdc_' на 'dog_' (или любую другую строку той же длины)
patched = content.replace(b'cdc_', b'dog_')
with open(driver_path, 'wb') as f:
f.write(patched)
print(f'ChromeDriver патчен: {driver_path}')
# Использование
patch_chromedriver('/path/to/chromedriver')
Внимание: Модификация бинарного файла ChromeDriver может нарушить его работу. Всегда делайте резервную копию перед патчингом. Этот метод работает не со всеми версиями ChromeDriver.
Метод 3: Использование undetected-chromedriver
Библиотека undetected-chromedriver автоматически патчит ChromeDriver при запуске:
pip install undetected-chromedriver
import undetected_chromedriver as uc
# Создание драйвера с автоматическим патчингом
driver = uc.Chrome()
driver.get('https://nowsecure.nl/') # Сайт для проверки детекции
input('Нажмите Enter для закрытия...')
driver.quit()
Маскировка Canvas, WebGL и Audio API
Canvas, WebGL и Audio Fingerprinting — это методы создания уникального отпечатка на основе особенностей рендеринга графики и обработки звука. Каждая комбинация браузера, ОС и железа даёт уникальный результат.
Canvas Fingerprinting
Системы рисуют скрытое изображение на Canvas и анализируют получившиеся пиксели. Headless-браузеры часто дают нетипичные результаты из-за отсутствия GPU-ускорения.
// Типичный код Canvas Fingerprinting
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillText('Browser fingerprint', 2, 2);
const fingerprint = canvas.toDataURL();
Для защиты можно добавить случайный шум к Canvas API:
const canvasNoiseScript = `
// Добавляем случайный шум к Canvas
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
const originalToBlob = HTMLCanvasElement.prototype.toBlob;
const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
// Функция добавления шума
const addNoise = (canvas, context) => {
const imageData = originalGetImageData.call(context, 0, 0, canvas.width, canvas.height);
for (let i = 0; i < imageData.data.length; i += 4) {
// Добавляем минимальный шум к RGB (не заметен глазу)
imageData.data[i] += Math.floor(Math.random() * 3) - 1;
imageData.data[i + 1] += Math.floor(Math.random() * 3) - 1;
imageData.data[i + 2] += Math.floor(Math.random() * 3) - 1;
}
context.putImageData(imageData, 0, 0);
};
// Переопределяем toDataURL
HTMLCanvasElement.prototype.toDataURL = function() {
if (this.width > 0 && this.height > 0) {
const context = this.getContext('2d');
addNoise(this, context);
}
return originalToDataURL.apply(this, arguments);
};
`;
WebGL Fingerprinting
WebGL предоставляет информацию о видеокарте и драйверах. Headless-браузеры часто показывают SwiftShader (программный рендерер) вместо реальной GPU:
const webglMaskScript = `
// Маскируем WebGL параметры
const getParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function(parameter) {
// UNMASKED_VENDOR_WEBGL
if (parameter === 37445) {
return 'Intel Inc.';
}
// UNMASKED_RENDERER_WEBGL
if (parameter === 37446) {
return 'Intel Iris OpenGL Engine';
}
return getParameter.call(this, parameter);
};
// Также для WebGL2
if (typeof WebGL2RenderingContext !== 'undefined') {
const getParameter2 = WebGL2RenderingContext.prototype.getParameter;
WebGL2RenderingContext.prototype.getParameter = function(parameter) {
if (parameter === 37445) {
return 'Intel Inc.';
}
if (parameter === 37446) {
return 'Intel Iris OpenGL Engine';
}
return getParameter2.call(this, parameter);
};
}
`;
Audio Context Fingerprinting
Audio API также даёт уникальный отпечаток. Добавляем шум к аудио-обработке:
const audioMaskScript = `
// Добавляем шум к Audio Context
const AudioContext = window.AudioContext || window.webkitAudioContext;
if (AudioContext) {
const originalCreateAnalyser = AudioContext.prototype.createAnalyser;
AudioContext.prototype.createAnalyser = function() {
const analyser = originalCreateAnalyser.call(this);
const originalGetFloatFrequencyData = analyser.getFloatFrequencyData;
analyser.getFloatFrequencyData = function(array) {
originalGetFloatFrequencyData.call(this, array);
// Добавляем минимальный шум
for (let i = 0; i < array.length; i++) {
array[i] += Math.random() * 0.0001;
}
};
return analyser;
};
}
`;
Имитация человеческого поведения
Даже с идеальной технической маскировкой боты выдают себя поведением. Системы машинного обучения анализируют паттерны движений мыши, скорость действий и последовательность событий.
Случайные задержки между действиями
Никогда не используйте фиксированные задержки. Реальные пользователи делают паузы разной длительности:
import random
import time
def human_delay(min_seconds=1, max_seconds=3):
"""Случайная задержка имитирующая человека"""
delay = random.uniform(min_seconds, max_seconds)
time.sleep(delay)
# Использование
driver.get('https://example.com')
human_delay(2, 4) # Пауза 2-4 секунды
element = driver.find_element(By.ID, 'search')
human_delay(0.5, 1.5) # Короткая пауза перед вводом
element.send_keys('search query')
human_delay(1, 2)
Плавное движение мыши
Боты двигают мышь по прямым линиям или телепортируют курсор. Реальные пользователи создают кривые траектории с ускорением и замедлением:
// Puppeteer: плавное движение мыши
async function humanMouseMove(page, targetX, targetY) {
const steps = 25; // Количество промежуточных точек
const currentPos = await page.evaluate(() => ({
x: window.mouseX || 0,
y: window.mouseY || 0
}));
for (let i = 0; i <= steps; i++) {
const t = i / steps;
// Используем easing для плавности
const ease = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
const x = currentPos.x + (targetX - currentPos.x) * ease;
const y = currentPos.y + (targetY - currentPos.y) * ease;
await page.mouse.move(x, y);
await page.waitForTimeout(Math.random() * 10 + 5);
}
// Сохраняем позицию
await page.evaluate((x, y) => {
window.mouseX = x;
window.mouseY = y;
}, targetX, targetY);
}
// Использование
await humanMouseMove(page, 500, 300);
await page.mouse.click(500, 300);
Естественный скроллинг
Реальные пользователи скроллят плавно, с остановками для чтения контента:
async function humanScroll(page) {
const scrollHeight = await page.evaluate(() => document.body.scrollHeight);
const viewportHeight = await page.evaluate(() => window.innerHeight);
let currentPosition = 0;
while (currentPosition < scrollHeight - viewportHeight) {
// Случайный шаг скролла (200-500px)
const scrollStep = Math.floor(Math.random() * 300) + 200;
currentPosition += scrollStep;
// Плавный скролл
await page.evaluate((pos) => {
window.scrollTo({
top: pos,
behavior: 'smooth'
});
}, currentPosition);
// Пауза для "чтения" контента (1-3 секунды)
await page.waitForTimeout(Math.random() * 2000 + 1000);
}
}
// Использование
await page.goto('https://example.com');
await humanScroll(page);
Естественный ввод текста
Люди печатают с разной скоростью, делают опечатки и исправляют их:
async function humanTypeText(page, selector, text) {
await page.click(selector);
for (let char of text) {
// Случайная задержка между нажатиями (50-200ms)
const delay = Math.random() * 150 + 50;
await page.waitForTimeout(delay);
// 5% шанс опечатки
if (Math.random() < 0.05) {
// Печатаем случайный символ
const wrongChar = String.fromCharCode(97 + Math.floor(Math.random() * 26));
await page.keyboard.type(wrongChar);
await page.waitForTimeout(100 + Math.random() * 100);
// Удаляем (Backspace)
await page.keyboard.press('Backspace');
await page.waitForTimeout(50 + Math.random() * 50);
}
await page.keyboard.type(char);
}
}
// Использование
await humanTypeText(page, '#search-input', 'example search query');
Интеграция прокси для полной анонимности
Маскировка браузера бесполезна, если все запросы идут с одного IP-адреса. Системы антибот-защиты отслеживают количество запросов с каждого IP и блокируют подозрительную активность. Прокси — обязательный компонент любой серьёзной автоматизации.
Выбор типа прокси
Разные задачи требуют разных типов прокси:
| Тип прокси | Преимущества | Применение |
|---|