Задача звучала скучно: собирать выдачу Google. Много, регулярно, через обычные резидентные прокси и без платных SERP API.
Первая версия честно открывала Chrome, вбивала запрос и получала капчу. Вторая получала капчу чуть реже. Где-то между двадцатым экспериментом и вкладкой, которая съела 3 гигабайта памяти, стало понятно, что мы всё это время думали о Google неправильно.
В итоге получился открытый инструмент, google-browser-scraper (GitHub, MIT): настоящий Chrome под Patchright, который отдаёт выдачу в JSON. Но эта статья не про код. Она про то, что мы намерили по дороге, и про то, что не сработало. Конкретных рецептов обхода здесь не будет: только что мерили, как мерили и что увидели.
Сначала про то, как мы считали
Всё, что ниже, — это прогоны на сервере с Windows, через резидентные прокси, обычно новый IP на каждый тест. Успех — это когда Google отдал страницу с результатами. Капча, блок, «необычный трафик» — отказ. Отказ мы никогда не записываем как «0 результатов»: в JSON у каждой страницы есть явный вердикт. Звучит очевидно, но иначе о проблеме узнаёшь через неделю по странной статистике.
И одно правило, которое мы выучили больно: сравнивать варианты можно только в одном окне времени, вперемешку. У Google бывают дни, когда не проходит ничего, и дни, когда проходит половина. Если вариант А мерили во вторник, а Б в среду, вы сравнили вторник со средой.
Headless убивает всё, а мы искали причину где угодно, кроме него
Однажды контрольные прогоны перестали работать. Совсем.
|
Режим браузера |
Обслужено запросов |
|---|---|
|
headless |
0 из 35 |
|
обычное окно |
149 из 150 |
Сначала мы решили, что неудачный час. Потом — что неудачный день. Потом придумали третье объяснение. И только после гигабайта сожжённого трафика сравнили настройки с прогоном, который работал, и нашли --headless, который случайно попал в проверочный скрипт.
Мораль, которую я теперь повторяю себе каждый раз: если что-то сломалось, сначала ищи, чем этот запуск отличается от работающего. Объяснение, которое хорошо звучит, — не то же самое, что причина.
Свежий браузер Google не любит. Браузер с историей — любит
Чистый профиль на чистом IP, который сразу идёт искать, проходит редко. Тот же профиль, который сначала походил по обычным сайтам, проходит в разы чаще:
|
|
Пропущено IP |
|---|---|
|
сразу в поиск |
11 из 44 |
|
сначала обычные сайты |
36 из 44 |
Важно оказалось не только куда ходить, но и как долго оставаться. Короткие визиты помогали заметно хуже, чем визиты, похожие на чтение. Когда мы удлинили их, доля пропущенных свежих IP выросла почти вдвое.
Цена у этого есть: прогрев одного IP стоит десятки мегабайт трафика. Поэтому вся остальная история — о том, как платить за него реже.
Google доверяет не IP, а профилю
Это главный эксперимент. Берём профиль браузера, который Google уже пропустил, и переносим его на другой, новый IP.
|
Что попало на новый IP |
Пропущено |
|---|---|
|
свежий профиль |
2 из 16 |
|
профиль, который Google уже пропустил |
23 из 35 |
|
тот же профиль, но без кук Google |
0 из 12 |
Новый IP, ни одного запроса с него раньше — и Google пропускает, если браузер «тот же». Убери куки Google — и доверие пропадает целиком.
Для меня это поменяло картину. IP — это проверка на входе, а репутацию несёт профиль. Отсюда и практическое следствие для любого скрейпера: прогретый профиль ценнее прогретого IP, и терять его на каждой смене прокси — значит каждый раз платить заново.
Один IP держит тысячу запросов, и каждый следующий дешевле
Сначала мы меняли IP каждые 10 запросов, «на всякий случай». Потом каждые 50. Потом решили наконец проверить, где предел.
Предела мы не нашли. За три с лишним тысячи запросов на уже пропущенных IP Google не отказал ни разу. Удержание заканчивалось, когда отваливался сам резидентный IP, а один IP отработал 1210 запросов подряд, и тест остановили мы, а не Google.
Бонус, которого мы не ждали: страница дешевеет по мере удержания, потому что прогревается кэш браузера.
|
Запросы на одном IP |
Трафик внутри страницы |
|---|---|
|
1-50 |
~0,9 MB |
|
51-100 |
~0,6 MB |
|
200+ |
~0,4 MB |
Бесконечно дешеветь она, конечно, не может. После ~200-го запроса цена встаёт на плато и стоит там тысячу запросов подряд. Всё общее (скрипты, стили, картинки Google) уже в кэше, а остаётся то, что уникально для каждого запроса: HTML выдачи, превью, фоновые запросы. Это не закэшировать, поэтому около 0,65 MB на запрос — потолок экономии даже для IP, который живёт вечно.
Кэш можно унести с собой
Раз страницу удешевляет кэш, а доверие живёт в профиле, коллега предложил очевидное: переносить на новый IP профиль вместе с кэшем. Проверили в одном окне, вперемешку:
|
Что перенесли на новый IP |
Трафик на поиск, всё включено |
|---|---|
|
профиль без кэша |
~1,1 MB |
|
профиль с кэшем |
~0,73 MB |
Минус треть трафика на старте каждого нового IP. Google это не смутило: в обоих вариантах обслужены все поиски.
Вкладка Google на 3 гигабайта
Когда мы стали держать один IP по 500+ запросов, скрейпер начал падать с MemoryError. Python был ни при чём. Журнал Windows показал, что процесс-рендерер вкладки с Google вырос до 3,2 GB за 548 поисков. А после падения скрейпера этот процесс продолжал висеть и держать память.
Первая идея — открывать новую вкладку раз в N поисков — не сработала вообще: память росла с той же скоростью. Моя гипотеза (не проверенная): Chrome держит вкладки одного сайта в одном процессе, и новая вкладка садится в тот же раздутый процесс. Сработал только перезапуск браузера: память идёт пилой, кэш на диске остаётся, а Google после перезапуска продолжает пускать. С этим контрольный прогон на 1000 запросов в два браузера прошёл без единой ошибки памяти.
А время суток вообще важно?
Я был уверен, что да: у нас даже прогоны стояли на вечер, «потому что вечером Google добрее». По сырым цифрам так и выходило: вечером проходило вдвое больше, чем ночью.
Потом мы сравнили часы внутри одного дня, и разница почти исчезла: лучшее окно (16-19 UTC) выигрывает у среднего за день около трёх пунктов. «Вдвое» давали не часы, а дни: прогоны в плохие дни случайно чаще попадали на ночь. Время суток почти не важно. День важен очень. А прогретый браузер проходит в 84% случаев в любое время.
Что не сработало
Пожалуй, самая полезная часть.
-
Уходить со страницы сразу после чтения. Экономит 35-45% трафика, но Google начал отказывать посреди удержания у 3 IP из 10, а без этого — у 0 из 6. Не стоит того.
-
Прогреть в Chrome, а искать лёгким клиентом. Идея красивая: дорогой браузер только для прогрева, дальше curl_cffi или Obscura с теми же куками. 0 из 50. Google пускал Chrome и не пускал лёгкий клиент с той же «историей».
-
Новая вкладка вместо перезапуска браузера — см. выше.
Сколько это стоит
Контрольный прогон последней версии: 1000 запросов из 1000, около 1 GB резидентного трафика вместе с прогревом, 1 час 40 минут в два браузера на сервере с 4 ядрами. При длинном удержании IP — около 0,8 GB на тысячу. Это заметно дешевле премиальных SERP API, хотя и немного медленнее: около 8-10 секунд на запрос на один браузер против 3-5 секунд у API.
Что я вынес
-
Google оценивает браузер, а не IP. IP — проверка на входе.
-
Тот, кого Google уже пустил, может делать сотни запросов. Дорого только начало.
-
Если результат внезапно поменялся, ищите, что поменялось у вас, прежде чем винить Google.
-
Сравнивайте варианты только в одном окне времени. Дни у Google слишком разные.
Попробовать
pip install google-browser-scraperpatchright install chromiumgoogle-browser-scraper search "best running shoes" \ --proxy "http://USER-session-{session}:PASS@gate.example.com:7000" \ -o results.jsonl
Нужен любой резидентный прокси со sticky-сессиями. Все замеры в статье сделаны на прокси NodeMaven, с ними сессии настраиваются флагом --nodemaven. Ещё есть Docker-образ, локальный HTTP API в привычном формате SERP API и MCP-сервер, через который AI-агент получает живой поиск Google.
Если у вас на других прокси или другой ОС получается иначе, напишите в issues. Мне правда интересно, где наши выводы не держатся.
ссылка на оригинал статьи https://habr.com/ru/articles/1097926/