Google обрабатывает миллиарды поисковых запросов в день, а страница результатов за каждым запросом, это структурированный снимок того, что ранжируется по запросу: органические заголовки, ссылки, на которые они указывают, и текст фрагмента под каждым из них. Это делает публичный SERP Google полезным сигналом для исследования ключевых слов, отслеживания позиций и анализа конкурентов. Данные находятся прямо на странице результатов; задача, получить их надёжным способом.
Это сфокусированная, работоспособная версия этой задачи. Вы настроите Python, получите отрисованную страницу результатов Google через Crawling API, спарсите каждый органический результат в заголовок, ссылку и фрагмент, перейдёте по более глубоким результатам и экспортируете в JSON и CSV. Руководство ограничено публичными данными результатов поиска, которые любой может видеть без учётной записи. Для широкого обзора структуры SERP, нескольких подходов и масштабирования прочитайте широкий материал как парсить страницы поиска Google; этот пост сосредоточен и создаёт рабочий скрапер.
Что вы создадите
Скрипт на Python, который принимает поисковый запрос, получает отрисованную страницу результатов Google через Crawling API и возвращает чистую запись для каждого органического результата на странице. В качестве рабочего примера мы используем образцовый запрос и извлекаем следующие поля из каждого результата:
- Позиция, ранг результата на странице, считая от верха.
- Заголовок, текст заголовка результата, как показан в объявлении.
- Ссылка, URL назначения, на который указывает результат.
- Фрагмент, отображаемое описание или резюме под заголовком.
- Похожие поисковые запросы, предлагаемые дополнительные запросы, которые Google перечисляет внизу страницы.
Почему обычный запрос не работает на Google
Отправьте обычный HTTP-запрос к google.com/search из скрипта, и вы почти никогда не получите страницу, которую видите в браузере. Против вас работают две вещи. Во-первых, Google теперь опирается на JavaScript для отрисовки страницы результатов: начиная с 2025 года SERP требует выполнения скриптов, поэтому обычный запрос без выполнения JavaScript возвращает пустую оболочку вместо объявлений. Во-вторых, Google следит за автоматическим трафиком. Слишком много запросов с одного IP, слишком быстрые запросы или запросы, не похожие на запросы реального браузера, встречаются CAPTCHA, ограничением скорости или блокировкой.
Поэтому рабочий скрапер Google требует двух вещей в одном запросе: IP-адреса, который поисковая система воспринимает как обычного посетителя, и браузера, который отрисовывает страницу. Можно собрать это самостоятельно с помощью безголового браузера плюс пула ротирующихся резидентных прокси, но поддержание этого парка в рабочем состоянии, это большая часть всей работы. Crawling API объединяет обе вещи в одном вызове. Он также поставляется со встроенным скрапером google-serp, который получает отрисованную страницу с доверенного ротирующегося IP и возвращает органические результаты, уже разобранные в JSON, поэтому вам не нужно писать хрупкие селекторы для часто меняющейся разметки Google.
Предварительные требования
Перед написанием кода нужно подготовить несколько вещей. Ни одна из них не займёт много времени.
Базовые знания Python. Вы должны уверенно писать и запускать Python-скрипты и устанавливать пакеты через pip. Если вы новичок в скрапинге в целом, наше руководство по парсингу сайтов с Python охватывает основы, которые предполагает этот учебник.
Python 3.8 или новее. Проверьте версию командой python --version. Если Python не установлен, скачайте его с python.org или через дистрибутив вроде Anaconda. Подойдёт любой редактор: VS Code, PyCharm и Jupyter, все хороши для этого.
Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте панель управления и скопируйте токен запроса. Вы получаете до 20 000 бесплатных запросов, без кредитной карты, а встроенный скрапер google-serp работает с обычным токеном. Храните токен как пароль: он аутентифицирует ваши запросы, поэтому не добавляйте его в систему контроля версий.
Настройка проекта
Создайте виртуальное окружение, чтобы зависимости проекта оставались изолированными, затем установите библиотеку Crawlbase для Python, которая оборачивает Crawling API в небольшой клиент.
python --version python -m venv google_env source google_env/bin/activate pip install crawlbase
В Windows активируйте окружение командой google_env\Scripts\activate вместо строки с source. Пакет crawlbase предоставляет вам клиент CrawlingAPI, чтобы не нужно было строить URL запроса вручную. Поскольку скрапер google-serp возвращает разобранный JSON, в этом учебнике для органических результатов даже не нужна библиотека для парсинга HTML.
Шаг 1: Получение отрисованного SERP через Crawling API
Начните с получения данных. Напишите небольшую функцию scrape_google_results(), которая строит URL поиска, отправляет его в Crawling API с включённым скрапером google-serp, проверяет статус и возвращает разобранное тело. Google пагинирует наборами по 10, поэтому функция принимает номер страницы и переводит его в смещение start, которое Google ожидает в URL.
import json from urllib.parse import quote_plus from crawlbase import CrawlingAPI # Replace with your token from the Crawlbase dashboard crawling_api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) def scrape_google_results(query, page=0): encoded = quote_plus(query) url = f"https://www.google.com/search?q={encoded}&start={page * 10}" options = {"scraper": "google-serp"} response = crawling_api.get(url, options) if response["headers"]["cb_status"] == "200": data = json.loads(response["body"].decode("latin1")) return data.get("body", {}) print(f"Failed to fetch results for '{query}' (page {page}).") return {} if __name__ == "__main__": results = scrape_google_results("web scraping tools", page=0) print(json.dumps(results.get("searchResults", [])[:2], indent=2))
Словарь options, это весь трюк: передача {"scraper": "google-serp"} сообщает Crawling API отрисовать страницу, обойти проверки ботов и вернуть SERP уже разобранным. Клиент возвращает ответ, headers["cb_status"] которого является собственным статусом Crawlbase для краулинга, поэтому проверка "200" перед парсингом делает блок или неудавшуюся отрисовку заметными, а не передаёт мусор вниз. Тело возвращается в байтах, которые вы декодируете через latin1 и загружаете как JSON, затем считываете разобранный SERP из его ключа body. Запустите скрипт, и вы должны увидеть первые два органических результата в виде JSON, что подтверждает работоспособность получения и парсинга данных перед построением чего-либо поверх.
cb_status (legacy pc_status) читает 200, потому что запрос достиг Google как реальный посетитель, с отрисованной страницей и обработанными проверками ботов, прежде чем скрапер google-serp превратил его в только что напечатанный JSON. Crawling API выполняет JavaScript-отрисовку и ротирует резидентные IP на стороне сервера, поэтому вам не нужно запускать парк безголовых браузеров и самостоятельно искать пул прокси. Начните с бесплатного тарифа и сначала направьте его на публичный URL результатов.
Шаг 2: Парсинг органических результатов в чистые записи
Скрапер google-serp возвращает SERP уже структурированным, поэтому парсинг, это вопрос считывания нужных полей, а не написания CSS-селекторов. Органические объявления находятся под ключом searchResults, каждое содержит position, title, url и description. Страница также возвращает relatedSearches, а скрапер показывает ads, peopleAlsoAsk и локальный snackPack, когда запрос их активирует. Напишите небольшую функцию, которая выбирает нужные поля и нормализует имя поля фрагмента.
def parse_results(serp): organic = [] for item in serp.get("searchResults", []): organic.append({ "position": item.get("position"), "title": item.get("title"), "link": item.get("url"), "snippet": item.get("description"), }) related = [r.get("title") for r in serp.get("relatedSearches", [])] return {"organic": organic, "relatedSearches": related}
Это сохраняет четыре поля, которые нужны большинству задач отслеживания позиций и исследований: position прямо от Google, title, ссылка назначения link (считана из поля url результата) и snippet (считан из description). Извлечение relatedSearches вместе с этим даёт вам предлагаемые дополнительные запросы бесплатно, что удобно для расширения ключевых слов. Поскольку скрапер выполняет извлечение полей, вы защищены от изменений разметки Google; вы всегда работаете только с этими стабильными JSON-ключами.
Можно получить исходный отрисованный HTML и спарсить его с помощью BeautifulSoup, но имена классов контейнеров результатов Google обфусцированы и часто меняются, поэтому написанные вручную селекторы регулярно ломаются. Скрапер google-serp вместо этого возвращает стабильные JSON-ключи, такие как searchResults, position и relatedSearches, что требует значительно меньше обслуживания. Если вы хотите подход с селекторами для других сайтов, наше руководство по XPath и CSS-селекторам охватывает это.
Шаг 3: Обработка пагинации
Одна страница, это демонстрация; реальная задача требует более глубокого погружения в результаты. Google пагинирует наборами по 10 через параметр start, так что вторая страница, это start=10, третья, start=20, и так далее, математику преобразования страницы в смещение в scrape_google_results уже обрабатывает. Переберите диапазон страниц, останавливайтесь досрочно, когда страница возвращается пустой, и собирайте все органические записи в один список. Дозирование цикла с коротким паузой поддерживает длительный запуск в рабочем состоянии.
import time def scrape_all_pages(query, max_pages=3): all_organic = [] for page in range(max_pages): print(f"Scraping page {page + 1}...") serp = scrape_google_results(query, page) parsed = parse_results(serp) if not parsed["organic"]: print("No more results, stopping.") break all_organic.extend(parsed["organic"]) time.sleep(2) return all_organic
Цикл идёт от страницы 0 до max_pages, получает каждую страницу, парсит её и расширяет текущий список. Защита if not parsed["organic"]: break останавливается в момент, когда страница не содержит органических результатов, поэтому вы не продолжаете платить за пустые страницы за пределами объявлений. time.sleep(2) между страницами распределяет запросы вместо того, чтобы отправлять их в плотном цикле, что является единственной лучшей привычкой для поддержания разблокированного состояния при длительном запуске.
Шаг 4: Сборка полного скрипта и экспорт
Теперь свяжите получение, парсинг и пагинацию в один работоспособный скрипт и запишите вывод в JSON и CSV. JSON сохраняет полную вложенную структуру; CSV даёт вам плоскую таблицу, которую можно открыть в таблице для быстрой проверки позиций.
import csv import json import time from urllib.parse import quote_plus from crawlbase import CrawlingAPI crawling_api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) def scrape_google_results(query, page=0): encoded = quote_plus(query) url = f"https://www.google.com/search?q={encoded}&start={page * 10}" options = {"scraper": "google-serp"} response = crawling_api.get(url, options) if response["headers"]["cb_status"] == "200": data = json.loads(response["body"].decode("latin1")) return data.get("body", {}) print(f"Failed to fetch results for '{query}' (page {page}).") return {} def parse_results(serp): organic = [] for item in serp.get("searchResults", []): organic.append({ "position": item.get("position"), "title": item.get("title"), "link": item.get("url"), "snippet": item.get("description"), }) return organic def scrape_all_pages(query, max_pages=3): all_organic = [] for page in range(max_pages): print(f"Scraping page {page + 1}...") organic = parse_results(scrape_google_results(query, page)) if not organic: print("No more results, stopping.") break all_organic.extend(organic) time.sleep(2) return all_organic def save_json(rows, filename): with open(filename, "w", encoding="utf-8") as f: json.dump(rows, f, ensure_ascii=False, indent=2) def save_csv(rows, filename): fields = ["position", "title", "link", "snippet"] with open(filename, "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=fields) writer.writeheader() writer.writerows(rows) if __name__ == "__main__": query = "web scraping tools" rows = scrape_all_pages(query, max_pages=2) save_json(rows, "google_results.json") save_csv(rows, "google_results.csv") print(f"Saved {len(rows)} results to JSON and CSV")
Запустите командой python main.py. Скрипт парсит две страницы для "web scraping tools", сводит каждый органический результат в один список и записывает google_results.json и google_results.csv. Чтобы парсить другой запрос, измените строку query; чтобы углубиться, увеличьте max_pages. Установка ensure_ascii=False сохраняет читаемость заголовков с не-латинскими символами в JSON-файле, а не экранирует их в последовательности \u.
Как выглядит вывод
JSON-файл представляет собой упорядоченный список органических записей, каждая с позицией, заголовком, ссылкой и фрагментом, готовых для загрузки в базу данных или лист отслеживания позиций.
[ { "position": 1, "title": "Web Scraper - The #1 web scraping extension", "link": "https://webscraper.io/", "snippet": "The most popular web scraping extension. Start scraping in minutes." }, { "position": 2, "title": "ParseHub | Free web scraping - The most powerful web scraper", "link": "https://www.parsehub.com/", "snippet": "ParseHub is a free web scraping tool. Turn any site into a spreadsheet or API." } ]
CSV содержит те же записи в виде плоской таблицы с одной строкой на результат и столбцами position, title, link и snippet, что является форматом, ожидаемым большинством таблиц отслеживания позиций.
Масштабирование по запросам и поддержание разблокированного состояния
Приведённый скрипт парсит один запрос по нескольким страницам. Производственная задача обычно запускает много запросов и может отслеживать их со временем, но форма не меняется: зациклите список запросов, вызывайте scrape_all_pages для каждого и помечайте каждую запись запросом, из которого она пришла, перед сохранением. Crawling API обрабатывает отрисовку и ротацию IP за каждый запрос, поэтому масштабирование в основном касается самодозирования и мониторинга статуса. Несколько привычек поддерживают длительный запуск в рабочем состоянии.
- Дозируйте запросы. Поддерживайте паузу между страницами и запросами, а не отправляйте их в плотном цикле. Распределение трафика, лучшая защита от вызовов.
-
Читайте статус. Следите за
cb_statusв каждом ответе. Запуск, который начинает давать сбои, сигнализирует о необходимости отступить, а не является шумом, который можно игнорировать. - Повторяйте при переходных сбоях. Любой ответ 5XX от API бесплатен, поэтому повтор неудачного краулинга ничего не стоит; короткий откат перед повтором обычно устраняет проблему.
- Опирайтесь на ротацию. Встроенная ротация резидентных адресов распределяет запросы по многим реальным адресам пользователей. Если вы предпочитаете маршрутизировать собственный трафик, Smart AI Proxy предоставляет ту же ротацию как прокси-эндпоинт.
Общее руководство по тактике см. в статье как парсить сайты без блокировок. Если вы также хотите извлечь блоки с вопросами, которые Google показывает посередине страницы, наше специализированное руководство по парсингу «Похожих вопросов» Google охватывает этот блок конкретно.
Законен ли парсинг результатов поиска Google?
Допустимость парсинга Google зависит от условий использования Google, вашей юрисдикции и того, как вы используете данные. Условия Google ограничивают автоматический доступ, поэтому парсинг может противоречить этим условиям вне зависимости от тщательности вашего инструментария. Ни один из приведённых здесь кодов не меняет этого; он лишь решает техническую часть задачи. Прочитайте условия Google и его robots.txt и рассматривайте оба документа как границу того, что вы собираете.
Несколько правил, которых стоит придерживаться. Собирайте только публичные данные результатов поиска: заголовки, ссылки, фрагменты и позиции, которые любой может видеть на странице результатов без учётной записи. Поддерживайте достаточно скромный объём запросов, чтобы не нагружать серверы Google, и дозируйте сканирование, а не запускайте его на полную мощность. Не собирайте личные данные, не получайте контент из-за логина и не распространяйте защищённые авторским правом медиа, которые вы находите через ссылки в результатах. Это правила, которые делают работу оправданной.
Если ваш проект требует санкционированного высокообъёмного доступа, Google предлагает официальные продукты для этого, включая Custom Search JSON API и программный поиск через Google Cloud, что является правильным путём для такого масштаба, а не более хитрый скрапер. Это руководство намеренно ограничено публичными страницами SERP, поскольку именно это позволяет сохранить чистоту работы. Для получения дополнительной информации о конкретных препятствиях, которые Google ставит перед скраперами, и о том, как ответственно с ними справляться, см. наш материал о сложностях парсинга результатов поиска Google.
Ключевые выводы
- Обычный запрос не работает на Google. SERP 2025 года требует JavaScript для отрисовки, и Google блокирует трафик с признаками скрапинга, поэтому нужна отрисовка плюс доверенный IP в одном запросе.
-
Скрапер google-serp берёт на себя основную работу. Передайте
{"scraper": "google-serp"}, и Crawling API отрисует страницу, обработает проверки ботов и вернёт SERP как разобранный JSON. -
Считывайте стабильные JSON-ключи, а не селекторы. Извлекайте
position,title,urlиdescriptionизsearchResults, что защищает вас от изменений разметки Google. -
Пагинация через смещение start. Увеличивайте
startкратно 10 для более глубокого погружения, останавливайтесь, когда страница не содержит органических результатов, и делайте паузу между страницами. - Оставайтесь в рамках публичных данных. Соблюдайте условия использования Google и robots.txt, поддерживайте скромный объём, предпочтите официальный Custom Search API для больших объёмов и никогда не работайте с личными или данными за логином.
Часто задаваемые вопросы
Почему обычный запрос возвращает пустую страницу от Google?
Начиная с 2025 года страница результатов Google требует JavaScript для отрисовки, поэтому обычный HTTP-запрос без выполнения скриптов возвращается как пустая или скелетная оболочка. Google также блокирует автоматический трафик. Получение данных через Crawling API со скрапером google-serp отрисовывает страницу с доверенного ротирующегося IP и возвращает объявления как разобранный JSON, поэтому вы получаете реальные результаты вместо пустой страницы.
Можно ли парсить результаты поиска Google с помощью Python?
Да. С библиотекой Crawlbase для Python вы вызываете Crawling API, включаете встроенный скрапер google-serp и считываете заголовки, ссылки, фрагменты и позиции прямо из возвращаемого JSON. API служит мостом, который доставляет ваш запрос в Google с доверенного IP с отрисованной страницей, поэтому запросы обрабатываются без блокировок. Для более широкого обзора SERP и других подходов см. более широкое руководство по парсингу страниц поиска Google.
Чем это отличается от более широкого руководства по парсингу Google?
Этот пост, сфокусированный, работоспособный учебник по Python: настройка, получение, парсинг органических результатов, пагинация и экспорт с кодом, который можно копировать. Более широкий материал как парсить страницы поиска Google охватывает полную структуру SERP (реклама, «Похожие вопросы», информационная панель, локальный пакет), несколько подходов и стратегию масштабирования. Начните здесь, если нужен код прямо сейчас; читайте более широкий материал для общей картины.
Как пагинировать через больше результатов Google?
Google пагинирует наборами по 10 через параметр запроса start: вторая страница, это start=10, третья, start=20, и так далее. Функция scrape_google_results переводит номер страницы в это смещение, а scrape_all_pages перебирает диапазон страниц, останавливаясь, когда страница не возвращает органических результатов. Поддерживайте короткую паузу между страницами для дозирования сканирования.
Нужно ли самостоятельно обрабатывать JavaScript при парсинге Google?
Нет. SERP Google требует JavaScript для отрисовки, но скрапер google-serp отрисовывает страницу на стороне сервера за вас, поэтому вам не нужно запускать безголовый браузер или управлять парком для отрисовки. Вы отправляете URL поиска с включённым скрапером и получаете полностью отрисованные, разобранные результаты.
Как хранить спарсенные результаты Google?
Подходит любой структурированный формат. Полный скрипт в этом руководстве записывает JSON-файл, сохраняющий вложенную структуру, и CSV-файл, дающий плоскую таблицу из позиции, заголовка, ссылки и фрагмента для таблиц. Оттуда вы можете загрузить записи в базу данных или конвейер отслеживания позиций. Оставайтесь в рамках публичных данных результатов поиска и избегайте всего, что за логином.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.
