Baidu, доминирующая поисковая система в Китае, и именно туда большинство китайских пользователей обращаются в первую очередь. Это делает его публичные результаты поиска полезным сигналом для тех, кто занимается исследованием ключевых слов, отслеживанием SEO, анализом рынка или просто хочет понять, что ранжируется на рынке, где Google не лидирует. Страница результатов содержит те же структурированные данные, которые нужны SERP-инструменту повсюду: заголовки, ссылки, сниппеты и порядок их отображения.
Это руководство показывает, как надёжно парсить результаты поиска Baidu на Python. Вы создадите небольшой готовый к запуску парсер, который получает отрендеренную страницу результатов через Crawling API, разбирает каждый результат с помощью BeautifulSoup и выводит чистые структурированные данные. Руководство ограничивается публичными данными результатов поиска, которые любой может видеть без аккаунта, а юридический раздел ближе к концу, не формальность, поэтому прочтите его перед запуском на реальных объёмах.
Что вы создадите
Скрипт на Python, который принимает публичный URL поиска Baidu, получает HTML через Crawling API и извлекает структурированную запись по каждому органическому результату на странице. В качестве примера используется тестовый запрос, из которого извлекаются следующие поля каждого результата:
- Заголовок текст заголовка результата, как он отображается в объявлении.
- Ссылка URL назначения, на который указывает результат.
- Сниппет отображаемое описание или краткое содержание под заголовком.
- Позиция ранг результата на странице, отсчитываемый сверху.
Почему обычный запрос не работает на Baidu
Если направить обычный HTTP-запрос на URL результатов Baidu из скрипта, вы редко получаете чистую страницу, видимую в браузере. Два фактора работают против вас. Во-первых, Baidu работает из Китая и корректирует возвращаемые данные в зависимости от IP запрашивающего, поэтому иностранный адрес датацентра может получить геошлюз или частичное содержимое. Во-вторых, Baidu отслеживает автоматизированный трафик: запросы, не похожие на настоящий браузер, получают вызов, страницу верификации или блокировку ещё до достижения объявлений.
Поэтому работающий парсер Baidu в одном запросе требует двух вещей: IP, который платформа воспринимает как реального посетителя, и, когда страница зависит от скриптов, браузера, который её рендерит. Можно собрать это самостоятельно с headless-браузером плюс пулом ротирующих резидентских прокси, но поддержание их в рабочем состоянии составляет большую часть работы. Crawling API объединяет и то, и другое в одном вызове: вы отправляете ему URL, он получает данные с доверенного резидентского IP и рендерит при необходимости, а возвращает готовый HTML для разбора.
Baidu геочувствителен в отличие от большинства западных целей. Запрос с резидентского IP выглядит как обычный посетитель, тогда как иностранный адрес датацентра, немедленный сигнал тревоги. Crawling API ротирует резидентские адреса на стороне сервера, поэтому вам не нужно самостоятельно находить и поддерживать этот пул. Можно начать с бесплатного тарифа до 20 000 запросов без необходимости вводить карту.
Предварительные требования
Перед написанием кода нужно подготовить несколько вещей. Это не займёт много времени.
Базовые знания Python. Вы должны уметь писать и запускать скрипт на Python и устанавливать пакеты через pip. Если BeautifulSoup для вас нов, наше руководство по использованию BeautifulSoup в Python охватывает основы разбора, которые предполагает этот материал.
Python 3.8 или выше. Проверьте версию командой python --version. Если Python не установлен, скачайте его с python.org или через дистрибутив вроде Anaconda.
Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте панель управления и скопируйте токен запроса со страницы документации аккаунта. Вы получаете до 20 000 бесплатных запросов: 1 000 при регистрации и больше по мере прохождения шагов онбординга. Обращайтесь с токеном как с паролем: он аутентифицирует ваши запросы, поэтому не включайте его в систему контроля версий.
Настройка проекта
Создайте виртуальное окружение для изоляции зависимостей проекта, затем установите две библиотеки, которые нужны парсеру.
python --version python -m venv baidu_env source baidu_env/bin/activate pip install requests beautifulsoup4
В Windows активируйте окружение командой baidu_env\Scripts\activate вместо строки с source. Две зависимости выполняют основную работу: requests отправляет HTTP-вызов к Crawling API, а beautifulsoup4 разбирает возвращаемый HTML, позволяя извлекать отдельные поля по CSS-селектору.
Шаг 1: Получить страницу через Crawling API
Начните с получения HTML. Напишите небольшую функцию crawl(), которая отправляет целевой URL в Crawling API с вашим токеном, проверяет, что базовая страница вернулась со статусом 200, и возвращает тело HTML. Проверка статуса перед разбором делает сбои заметными, а не молчаливыми.
import json import requests API_TOKEN = "YOUR_CRAWLBASE_TOKEN" # replace with your token API_ENDPOINT = "https://api.crawlbase.com/" def crawl(url): params = {"token": API_TOKEN, "url": url} response = requests.get(API_ENDPOINT, params=params) response.raise_for_status() data = json.loads(response.text) if data["original_status"] != 200: raise Exception(f"Unable to crawl '{url}'") return data["body"] if __name__ == "__main__": url = "https://www.baidu.com/s?ie=utf-8&wd=%E8%8B%B9%E6%9E%9C%20iPhone" html = crawl(url) print(html[:500])
API возвращает JSON-конверт, поэтому вы загружаете ответ через json.loads и читаете два поля: original_status, это статус, который сам Baidu вернул, а body, HTML страницы. Проверка original_status означает, что геошлюз или блокировка проявляется как исключение, а не передаёт мусор в парсер. Тестовый запрос, "苹果 iPhone" (apple iPhone), URL-закодированный в параметре wd, так Baidu передаёт поисковый запрос. Запустите скрипт командой python crawling.py и вы должны увидеть реальную разметку результатов в первых 500 символах, что подтверждает работу получения данных до написания первого селектора.
Проверка original_status читает 200 только потому, что запрос поступил в Baidu как реальный посетитель в первую очередь. Crawling API получает страницу с ротирующего резидентского IP в правильном регионе, рендерит её при необходимости и возвращает готовый HTML, поэтому вам не нужно запускать собственный headless-флот и самостоятельно находить резидентский пул прокси. Сначала укажите публичный URL результатов на бесплатном тарифе.
Шаг 2: Разобрать результаты с помощью BeautifulSoup
Имея HTML, загрузите его в BeautifulSoup и извлеките каждый результат по его селектору. Baidu оборачивает каждый органический результат в блок с заголовком и считывает ссылку назначения из якоря внутри него. Проверьте текущие имена классов в живой странице в инструментах разработчика браузера (правый клик, затем «Просмотр кода»); приведённые ниже селекторы соответствуют вёрстке на момент написания.
from bs4 import BeautifulSoup def scrape_html(html): soup = BeautifulSoup(html, "html.parser") page_title = soup.title.string if soup.title else None search_input = soup.find("input", {"name": "wd"}) search_query = search_input.get("value", "") if search_input else "" results = [] for position, block in enumerate(soup.select("div.title-box_4YBsj"), start=1): heading = block.select_one("h3.t") link = block.select_one("a[href]") snippet = block.find_next("div", class_="content-right_2s-H4") if not heading or not link: continue results.append({ "position": position, "title": heading.get_text(strip=True), "url": link["href"], "snippet": snippet.get_text(strip=True) if snippet else None, }) return { "pageTitle": page_title, "searchQuery": search_query, "results": results, }
Селектор div.title-box_4YBsj, это обёртка, которую Baidu использует для блока заголовка каждого результата, с заголовком в теге h3.t и ссылкой назначения в якоре внутри него. Считывание ссылки из href якоря держит URL отдельно от заголовка. enumerate(..., start=1) даёт позицию по мере обхода, поэтому ранг берётся из порядка на странице, а не из хрупкого атрибута. Защита if not heading or not link: continue пропускает всё, что не является реальным органическим результатом, исключая рекламу и случайную разметку из выходных данных. Сниппет считывается из контейнера описания, следующего за каждым заголовком, с возвратом None при его отсутствии.
Имена классов Baidu, такие как title-box_4YBsj и content-right_2s-H4, содержат генерируемый суффикс, который меняется при обновлении фронтенда Baidu. Воспринимайте приведённые выше селекторы как отправную точку, а не как контракт. Если поле возвращается пустым для каждого результата, повторно проверьте живую страницу в инструментах разработчика браузера и обновите селектор. Периодическое обновление селекторов, норма для любого производственного парсера, а не признак поломки.
Шаг 3: Собрать всё вместе
Теперь свяжите получение данных и разбор в один готовый к запуску скрипт. Получите отрендеренную страницу результатов, передайте HTML парсеру и запишите структурированные данные в JSON. Настройка ensure_ascii=False сохраняет китайские символы читаемыми в файле вместо их экранирования в последовательности \u.
import json import requests from bs4 import BeautifulSoup API_TOKEN = "YOUR_CRAWLBASE_TOKEN" API_ENDPOINT = "https://api.crawlbase.com/" def crawl(url): params = {"token": API_TOKEN, "url": url} response = requests.get(API_ENDPOINT, params=params) response.raise_for_status() data = json.loads(response.text) if data["original_status"] != 200: raise Exception(f"Unable to crawl '{url}'") return data["body"] def scrape_html(html): soup = BeautifulSoup(html, "html.parser") page_title = soup.title.string if soup.title else None search_input = soup.find("input", {"name": "wd"}) search_query = search_input.get("value", "") if search_input else "" results = [] for position, block in enumerate(soup.select("div.title-box_4YBsj"), start=1): heading = block.select_one("h3.t") link = block.select_one("a[href]") snippet = block.find_next("div", class_="content-right_2s-H4") if not heading or not link: continue results.append({ "position": position, "title": heading.get_text(strip=True), "url": link["href"], "snippet": snippet.get_text(strip=True) if snippet else None, }) return {"pageTitle": page_title, "searchQuery": search_query, "results": results} def main(): url = "https://www.baidu.com/s?ie=utf-8&wd=%E8%8B%B9%E6%9E%9C%20iPhone" html = crawl(url) data = scrape_html(html) with open("baidu_results.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"Saved {len(data['results'])} results") if __name__ == "__main__": main()
Запустите полный скрипт командой python main.py. Он получает страницу результатов для "苹果 iPhone", извлекает запись по каждому органическому объявлению и записывает всё в baidu_results.json. Те же две функции, это всё, что вам нужно: замените запрос в URL, и парсер обработает всё, что придёт в ответ.
Как выглядит результат
Вы получаете чистый структурированный объект с заголовком страницы, эхом поискового запроса и упорядоченным списком результатов, готовый к записи в JSON, CSV или базу данных.
{ "pageTitle": "苹果 iPhone_百度搜索", "searchQuery": "苹果 iPhone", "results": [ { "position": 1, "title": "Apple (中国大陆) - 官方网站", "url": "http://www.baidu.com/link?url=abc123", "snippet": "探索 iPhone、iPad、Mac 等 Apple 产品的全新阵容。" }, { "position": 2, "title": "iPhone - 维基百科", "url": "http://www.baidu.com/link?url=def456", "snippet": "iPhone 是苹果公司设计和销售的智能手机系列。" } ] }
Обратите внимание, что URL результатов возвращаются как редиректные ссылки baidu.com/link?url=..., а не конечные адреса назначения. Именно так Baidu обслуживает исходящие клики. Если нужен реальный адрес назначения, следуйте каждому редиректу отдельным запросом, но делайте это осторожно и при небольшом объёме, чтобы не умножать трафик против Baidu.
Масштабирование по страницам и запросам
Один запрос на одной странице, это демонстрация; реальная задача охватывает несколько поисков и уходит глубже в результаты. Baidu пагинирует с параметром запроса pn, который представляет собой смещение в кратных 10: pn=10, это вторая страница, pn=20, третья, и так далее. Структура остаётся той же: формируйте каждый URL, получайте его через Crawling API и разбирайте той же функцией. Единственная привычка, поддерживающая работоспособность длительного сеанса, соблюдение темпа: делайте паузу между запросами вместо их отправки в плотном цикле.
import time from urllib.parse import quote query = "苹果 iPhone" encoded = quote(query) all_results = [] for page in range(3): offset = page * 10 url = f"https://www.baidu.com/s?ie=utf-8&wd={encoded}&pn={offset}" html = crawl(url) all_results.extend(scrape_html(html)["results"]) time.sleep(3) print(f"Collected {len(all_results)} results across 3 pages")
Crawlbase по умолчанию обслуживает до 20 запросов в секунду, что даёт достаточно возможностей для парсера, соблюдающего темп; если реально нужно больше, служба поддержки может увеличить лимит. Любой ответ 5XX от API не тарифицируется, поэтому повторная попытка по заблокированному или недоступному URL ничего не стоит. Если вы предпочитаете маршрутизировать собственный трафик через ротирующий пул вместо управляемого API, Smart AI Proxy (также называемый AI Proxy) предоставляет ту же ротацию резидентских IP в виде drop-in прокси-эндпоинта.
Как оставаться незаблокированным
Даже при наличии доверенного IP Baidu отслеживает трафик, характерный для парсеров, и его проверки строже, чем у большинства, из-за специфики работы. Несколько привычек поддерживают работоспособность сеанса.
- Регулируйте темп запросов. Быстрый обход страниц результатов в плотном цикле, самый быстрый способ получить вызов. Распределяйте запросы и варьируйте запросы вместо постраничного обхода одного термина на полной скорости.
- Полагайтесь на ротацию. Пул резидентских IP распределяет запросы по множеству реальных пользовательских адресов, чтобы ни один не превысил лимит. Crawling API управляет этим за вас; если вы строите свой стек, именно эту часть нужно реализовать правильно.
- Читайте коды статусов. Если сеанс начинает возвращать вызовы или страницы верификации, это сигнал о том, что текущий темп или уровень IP недостаточен. Воспринимайте это как сигнал к снижению активности, а не как шум, который нужно игнорировать.
- Повторно проверяйте при пустых полях. Baidu периодически меняет разметку. Если результаты перестали разбираться, откройте живую страницу в инструментах разработчика и обновите селекторы.
Более широкий план действий описан в как парсить сайты без блокировок и подробнее в как обходить CAPTCHA при парсинге. Если нужная страница Baidu зависит от скриптов при рендеринге, наше руководство по парсингу JavaScript-сайтов объясняет, почему рендеринг важен и как его включить.
Законен ли парсинг Baidu?
Допустимость парсинга Baidu зависит от его условий использования, вашей юрисдикции и того, что вы делаете с данными. Условия использования Baidu ограничивают автоматизированный доступ, поэтому парсинг может нарушать эти условия независимо от тщательности вашего инструментария. Ни один из приведённых здесь примеров кода этого не меняет; он просто обеспечивает работу технической части. Ознакомьтесь с условиями Baidu и его robots.txt и воспринимайте оба документа как границу того, что вы собираете.
Несколько принципов, которых стоит придерживаться. Собирайте только публичные данные результатов поиска: заголовки, ссылки, сниппеты и позиции, которые любой может видеть на странице результатов без аккаунта. Поддерживайте объём запросов достаточно низким, чтобы не перегружать серверы Baidu, и соблюдайте темп обхода вместо работы на полной скорости. Baidu не публикует широко доступный официальный SERP API для подобного доступа, что является дополнительным аргументом в пользу скромного масштаба и уважения к правилам сайта.
Это руководство намеренно ограничено публичными страницами результатов поиска, поскольку именно это позволяет работе оставаться защищаемой. Оно не охватывает данные за логином, аккаунты или персональные данные, а также охраняемые авторским правом медиаматериалы из связанных источников. Только публичные данные SERP. Если вашему проекту нужно больше, официальное соглашение на данные, правильный путь, а не более хитрый парсер.
Ключевые выводы
- Baidu геочувствителен. Иностранный IP датацентра получает другую страницу или блокировку, поэтому нужен доверенный резидентский адрес для просмотра реальных результатов.
- Crawling API получает данные за реальным IP. Отправьте ему URL, он ротирует резидентские IP на стороне сервера, рендерит при необходимости и возвращает готовый HTML для разбора.
-
BeautifulSoup выполняет извлечение. Выбирайте каждый
div.title-box_4YBsj, затем считывайте заголовок, ссылку, сниппет и позицию из него, и ожидайте устаревания суффиксированных имён классов. -
Пагинация через смещение pn. Увеличивайте
pnв кратных 10 для углубления в результаты и задавайте темп с паузой между страницами. - Оставайтесь в рамках публичных данных. Соблюдайте условия использования Baidu и robots.txt, поддерживайте небольшой объём, поскольку нет открытого официального SERP API, и никогда не касайтесь аккаунтов или персональных данных.
Часто задаваемые вопросы
Почему обычный запрос не работает или возвращает неправильную страницу на Baidu?
Baidu работает из Китая и корректирует возвращаемые данные в зависимости от IP запрашивающего, поэтому вызов с иностранного адреса датацентра может получить геошлюз, частичное содержимое или страницу верификации вместо результатов, видимых в вашем браузере. Он также помечает трафик, не похожий на настоящий браузер. Получение данных через Crawling API, использующий ротирующие резидентские IP, делает запрос похожим на обычного посетителя, и вы получаете реальную страницу результатов.
Можно ли парсить результаты поиска Baidu на Python?
Да. С помощью requests и BeautifulSoup можно получить страницу результатов и извлечь заголовки, ссылки, сниппеты и позиции. Crawling API служит мостом, доставляющим ваш запрос в Baidu с доверенного IP, поэтому запросы обрабатываются без блокировок. Более широкое введение в Python смотрите в нашем руководстве по парсингу сайтов на Python.
Какие поля можно извлечь со страницы результатов Baidu?
В этом руководстве извлекаются четыре поля из каждого органического результата: заголовок, ссылка назначения, отображаемый сниппет и позиция на странице. Также захватываются заголовок страницы и эхо поискового запроса из поля wd. Ограничивайтесь публичными данными результатов поиска и избегайте всего за логином.
Нужен ли для парсинга Baidu JavaScript-рендеринг?
Обычно основные результаты загружаются без него, поэтому базового получения данных из этого руководства достаточно. Если вы столкнётесь со страницей, для заполнения которой нужен браузер, Crawling API предлагает опцию JavaScript-рендеринга, получающую страницу так, как это делал бы настоящий браузер. Наше руководство по парсингу JavaScript-страниц на Python объясняет, когда это необходимо.
Как пагинировать по большему числу результатов Baidu?
Используйте параметр запроса pn, который является смещением в кратных 10: pn=10, вторая страница, pn=20, третья, и так далее. Формируйте каждый URL страницы со смещением, получайте его через Crawling API, разбирайте той же функцией и делайте паузу несколько секунд между запросами для соблюдения темпа вместо агрессивного обхода.
Мои селекторы ничего не возвращают. Что изменилось?
Скорее всего, разметка Baidu. Имена классов, такие как title-box_4YBsj, содержат генерируемый суффикс, который меняется при обновлении фронтенда Baidu, поэтому работавшие в прошлом месяце селекторы могут сломаться. Повторно проверьте живую страницу результатов в инструментах разработчика браузера и обновите селекторы. Периодическое обновление, норма для любого производственного парсера.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

