Как Google обнаруживает парсеры SERP
Google вкладывает значительные ресурсы в защиту результатов поиска от автоматического доступа. Прежде чем вы сможете избежать блокировок, необходимо понять методы обнаружения, которые использует Google. Каждый метод нацелен на разный сигнал, и эффективный парсинг SERP требует одновременного учёта всех из них.
Полный обзор архитектуры парсинга SERP с прокси смотрите в нашем руководстве по парсингу SERP с прокси.
Обнаружение по IP
Первая линия защиты — анализ IP. Google отслеживает объём запросов с каждого IP-адреса и помечает те, которые превышают нормальные паттерны человеческого поиска. Конкретные сигналы:
- Частота запросов: более нескольких поисков в минуту с одного IP запускает ограничение скорости
- Репутация IP: известные диапазоны IP дата-центров подвергаются немедленной проверке
- Географическое несоответствие: IP из Германии, делающий англоязычные запросы для рынка США, вызывает подозрение
- Анализ ASN: Google определяет блоки IP, принадлежащие хостинг-провайдерам и реальным интернет-провайдерам
Цифровой отпечаток браузера
Помимо IP-адресов, Google анализирует сам запрос на предмет признаков автоматизации:
| Сигнал | Что проверяет Google | Красный флаг |
|---|---|---|
| User-Agent | Строка идентификации браузера и ОС | Отсутствует, устарел или несовместим с другими заголовками |
| Accept-заголовки | Предпочтения типа контента | Отсутствие Accept-Language или нестандартные значения |
| TLS-отпечаток | Характеристики SSL/TLS-рукопожатия | Отпечаток, совпадающий с известными HTTP-библиотеками |
| Выполнение JavaScript | Поведение клиентских скриптов | Отсутствие выполнения JavaScript (обнаружение headless) |
| Поведение cookies | Принятие и управление cookies | Запросы без cookies или с идентичными паттернами |
Подробнее об этих техниках читайте в нашей статье о том, как антибот-системы обнаруживают прокси.
Поведенческий анализ
Google анализирует паттерны запросов для обнаружения автоматизации:
- Тайминг запросов: идеально постоянные интервалы (например, ровно 3 секунды) выглядят неестественно
- Паттерны запросов: парсинг ключевых слов в алфавитном порядке выглядит автоматическим
- Поведение сессии: реальные пользователи просматривают несколько страниц, кликают по результатам — парсеры только загружают SERP
- Паттерны объёмов: внезапные всплески запросов с связанных IP говорят о координированном парсинге
Три уровня стратегии защиты от блокировок
Избегание блокировок Google требует многослойного подхода. Ни одна техника сама по себе недостаточна.
Уровень 1: Инфраструктура прокси
Выбор прокси — основа вашей стратегии защиты от блокировок. Резидентские прокси ProxyHat обеспечивают разнообразие IP и уровень доверия, необходимые для устойчивого парсинга SERP.
Уровень 2: Конфигурация запросов
Каждый HTTP-запрос должен выглядеть так, будто исходит от реального браузера. Заголовки, cookies и тайминг должны быть реалистичными.
Уровень 3: Поведенческие паттерны
Общий паттерн вашей активности должен имитировать естественное поисковое поведение — рандомизированные задержки, различные последовательности запросов и соответствующие объёмы.
Резидентские прокси: первая линия защиты
Самое эффективное изменение — переход с серверных на резидентские прокси. Вот почему резидентские IP принципиально отличаются с точки зрения Google:
- Резидентские IP принадлежат реальным провайдерам (Comcast, AT&T, BT, Deutsche Telekom), а не облачным провайдерам
- Google не может блокировать диапазоны резидентских IP без блокировки реальных пользователей
- Каждый IP имеет историю просмотров и репутацию, сформированную реальным пользователем
- Резидентские IP поддерживают геотаргетинг на уровне города
Конфигурация прокси для парсинга SERP
import requests
# ProxyHat residential proxy with automatic rotation
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
session = requests.Session()
session.proxies = {
"http": PROXY_URL,
"https": PROXY_URL,
}
# Each request automatically gets a new residential IP
response = session.get(
"https://www.google.com/search",
params={"q": "best proxy service", "num": 10, "hl": "en", "gl": "us"},
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"DNT": "1",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
},
timeout=15,
)
Смотрите документацию ProxyHat для расширенных настроек ротации и сессий.
Реалистичные заголовки запросов
Неполные или несовместимые заголовки — одна из самых частых причин блокировок. Вот полный реалистичный набор заголовков:
import random
# Rotate between realistic User-Agent strings
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15",
]
def get_headers():
ua = random.choice(USER_AGENTS)
headers = {
"User-Agent": ua,
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"DNT": "1",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Cache-Control": "max-age=0",
}
# Firefox has different Sec-Ch headers
if "Firefox" not in ua:
headers["Sec-Ch-Ua"] = '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"'
headers["Sec-Ch-Ua-Mobile"] = "?0"
headers["Sec-Ch-Ua-Platform"] = '"Windows"' if "Windows" in ua else '"macOS"'
return headers
Всегда обновляйте строки User-Agent актуальными версиями браузеров. Отправка User-Agent Chrome 90 в 2026 году — мгновенный красный флаг.
Ограничение скорости и тайминг запросов
Паттерн ваших запросов важен не меньше, чем сами запросы. Проверенные стратегии тайминга:
Случайные задержки
Никогда не используйте фиксированные интервалы между запросами. Рандомизируйте задержки для имитации человеческого поведения:
import time
import random
def human_delay():
"""Generate a realistic delay between searches."""
# Base delay: 3-8 seconds (normal browsing pace)
base = random.uniform(3, 8)
# Occasionally add longer pauses (simulating reading results)
if random.random() < 0.15:
base += random.uniform(10, 30)
# Rare very short delays (rapid refinement searches)
if random.random() < 0.05:
base = random.uniform(1, 2)
return base
# Usage in scraping loop
for keyword in keywords:
result = scrape_serp(keyword)
delay = human_delay()
time.sleep(delay)
Рекомендации по объёму запросов
| Тип прокси | Безопасных запросов/мин на IP | Макс. параллельных IP |
|---|---|---|
| Резидентские (ротация) | 1-2 | Без ограничений (пул ротируется) |
| Резидентские (липкая сессия) | 1 за 30 сек | Зависит от размера пула |
| Серверные | 1 за 60 сек | Ограничено количеством IP |
Обработка CAPTCHA и блокировок
Даже при лучших мерах предосторожности вы иногда столкнётесь с блокировками. Настройте парсер для корректной их обработки.
Обнаружение блокировок
def is_blocked(response):
"""Check if Google has blocked or challenged the request."""
# HTTP 429: Rate limited
if response.status_code == 429:
return "rate_limited"
# HTTP 503: Service unavailable (temporary block)
if response.status_code == 503:
return "service_unavailable"
text = response.text.lower()
# CAPTCHA detection
if "captcha" in text or "recaptcha" in text:
return "captcha"
# Unusual traffic message
if "unusual traffic" in text or "automated queries" in text:
return "unusual_traffic"
# Empty or suspicious results
if "did not match any documents" in text and len(text) < 5000:
return "empty_suspicious"
return None
Стратегия повторных попыток
import time
import random
def scrape_with_retry(keyword, max_retries=3):
"""Scrape a SERP with automatic retry on blocks."""
for attempt in range(max_retries):
proxy_url = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
proxies = {"http": proxy_url, "https": proxy_url}
response = requests.get(
"https://www.google.com/search",
params={"q": keyword, "num": 10, "hl": "en", "gl": "us"},
headers=get_headers(),
proxies=proxies,
timeout=15,
)
block_type = is_blocked(response)
if block_type is None:
return parse_results(response.text)
if block_type == "rate_limited":
# Exponential backoff
wait = (2 ** attempt) * 5 + random.uniform(0, 5)
print(f"Rate limited. Waiting {wait:.1f}s (attempt {attempt + 1})")
time.sleep(wait)
elif block_type == "captcha":
# Switch to a new IP and wait
print(f"CAPTCHA detected. Rotating IP and waiting...")
time.sleep(random.uniform(10, 20))
else:
# Generic block: wait and retry
time.sleep(random.uniform(5, 15))
return None # All retries exhausted
Географическая согласованность
Тонкая, но важная мера антиобнаружения — обеспечение географической согласованности параметров запроса:
- Если IP прокси находится в США, установите
gl=usиhl=en - Согласуйте заголовок Accept-Language с целевой локалью
- Используйте User-Agent для ОС/браузера, распространённых в этой стране
- Учитывайте часовой пояс при планировании запросов
Функция геотаргетинга ProxyHat позволяет выбирать прокси из конкретных стран и городов. Подробнее об использовании локализованных запросов в нашем руководстве по парсингу без блокировок.
Реализация защиты от блокировок на Node.js
Вот аналогичная стратегия на Node.js:
const axios = require('axios');
const cheerio = require('cheerio');
const { HttpsProxyAgent } = require('https-proxy-agent');
const USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0',
];
function getRandomUA() {
return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function scrapeWithRetry(keyword, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const agent = new HttpsProxyAgent('http://USERNAME:PASSWORD@gate.proxyhat.com:8080');
try {
const { data, status } = await axios.get('https://www.google.com/search', {
params: { q: keyword, num: 10, hl: 'en', gl: 'us' },
headers: {
'User-Agent': getRandomUA(),
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'en-US,en;q=0.9',
},
httpsAgent: agent,
timeout: 15000,
validateStatus: () => true,
});
if (status === 429) {
const wait = Math.pow(2, attempt) * 5000 + Math.random() * 5000;
console.log(`Rate limited. Waiting ${(wait/1000).toFixed(1)}s`);
await sleep(wait);
continue;
}
if (data.toLowerCase().includes('captcha')) {
console.log('CAPTCHA detected. Rotating IP...');
await sleep(10000 + Math.random() * 10000);
continue;
}
return cheerio.load(data);
} catch (err) {
console.log(`Attempt ${attempt + 1} failed: ${err.message}`);
await sleep(5000 + Math.random() * 10000);
}
}
return null;
}
Продвинутые техники
Рандомизация запросов
Не парсите ключевые слова в алфавитном или последовательном порядке. Перемешивайте список перед каждым запуском:
import random
keywords = ["proxy service", "web scraping", "serp tracking", "seo tools"]
random.shuffle(keywords)
# Now scrape in random order
for kw in keywords:
scrape_with_retry(kw)
Параметры поиска Google
Используйте эти параметры для получения чистых неперсонализированных результатов:
| Параметр | Значение | Назначение |
|---|---|---|
pws | 0 | Отключить персонализированные результаты |
gl | Код страны | Установить страну поиска |
hl | Код языка | Установить язык интерфейса |
num | 10-100 | Результатов на страницу |
filter | 0 | Отключить фильтрацию дубликатов |
nfpr | 1 | Отключить автоисправление |
Распределённое планирование
Для масштабного SERP-мониторинга распределяйте запросы во времени. Вместо парсинга 10 000 ключевых слов за один час распределяйте их на 8-12 часов с естественными кривыми трафика (больше запросов в рабочее время, меньше ночью).
Цель — не просто избежать блокировок, а сделать ваш трафик неотличимым от обычного пользовательского поведения. Каждая деталь имеет значение.
Подробнее о создании надёжных масштабных пайплайнов парсинга читайте в нашем полном руководстве по прокси для веб-скрапинга и на странице решений ProxyHat для веб-скрапинга.






