# Baidu Maps Scraper — POIs, Phones, Ratings & Coordinates (`logiover/baidu-maps-scraper`) Actor

Baidu Maps (百度地图) scraper: export places from any Chinese city, district or radius with address, admin codes, phones, categories, rating, price per person, reviews, opening hours and WGS-84 / GCJ-02 / BD-09 coordinates. No 200-result cap, no login, no API key.

- **URL**: https://apify.com/logiover/baidu-maps-scraper.md
- **Developed by:** [Logiover](https://apify.com/logiover) (community)
- **Categories:** Lead generation, Travel, Marketing
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Baidu Maps Scraper

**Export every place Baidu Maps (百度地图) knows in any Chinese city, district, province or radius — name, address, phone, category, rating, reviews, price per person, opening hours, and GPS coordinates in WGS-84, GCJ-02 and BD-09.**

**Baidu Maps Scraper** is a Baidu Maps data extractor (百度地图数据采集 / 百度地图 POI 数据导出) that turns any Baidu Maps search into a clean spreadsheet: type what you are looking for (咖啡 coffee shops, 火锅 hotpot, 餐厅 restaurants, 酒店 hotels, 银行 banks, 医院 hospitals, 超市 supermarkets, 加油站 gas stations, 药店 pharmacies, 健身 gyms, 学校 schools, or a brand such as 星巴克 Starbucks or 瑞幸咖啡 Luckin) and where (北京 Beijing, 上海 Shanghai, 深圳 Shenzhen, 广东 Guangdong, 海淀区 Haidian district, or a point + radius), and the Actor scrapes Baidu Maps for every matching place — not just the ~150–200 results a single Baidu search shows. Each place comes with its Baidu `uid`, full Chinese address split into province / city / district / town / street / street number with 6-digit admin codes (行政区划代码), phone number in local and international (E.164) format, category path (美食 › 咖啡厅), brand, star rating and review count, price per person (人均消费) in CNY, opening hours for the whole week, place photo, status (open / temporarily closed), and coordinates in three systems at once: WGS-84 (GPS / Google Maps / OpenStreetMap), GCJ-02 (Amap / Gaode 高德, Tencent Maps, Apple Maps in China) and BD-09 (Baidu's own). It works as a **Baidu Maps API alternative** with **no API key, no login, no Baidu developer account and no browser** on your side, and you can **export Baidu Maps to CSV, Excel or JSON**, or pull the data straight into your CRM, database or AI agent.

For **China lead generation and market mapping**, the Actor reads Baidu's own top results first and then splits the whole area into map circles until every circle is complete, so you can scrape 10,000+ places in one run (10,302 Shanghai coffee-related POIs in one measured run, zero duplicates by `uid`). Use it to extract phone numbers from Baidu Maps, build China B2B lead lists with verified addresses and admin codes, map every competitor branch in a province, plan franchise expansion across prefecture-level cities, enrich a CRM with stable Baidu `uid`s, audit local listings, or feed structured China POI data to an AI agent that needs ground truth inside China — where Google Maps coverage is thin and Baidu is the directory businesses actually maintain.

All numbers on this page were measured on the Apify platform in **October 2026** (see [How much data can I get](#how-much-data-can-i-get-from-baidu-maps)).

> **Disclaimer:** This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Baidu, Inc. or Baidu Maps (百度地图). "Baidu Maps" and 百度地图 are trademarks of their respective owners.

***

### Table of contents

- [At a glance](#at-a-glance)
- [What you get](#what-you-get-the-baidu-maps-data-fields)
- [Who uses this Baidu Maps scraper](#who-uses-this-baidu-maps-scraper)
- [Cookbook: 16 ready-to-run inputs](#cookbook-16-ready-to-run-inputs)
- [Keyword cheat-sheet: Chinese keywords per vertical](#keyword-cheat-sheet-what-to-type-for-each-vertical)
- [Recipe: weekly refresh and diff](#recipe-weekly-refresh-and-openingclosure-diff-python)
- [Tutorial: scrape Baidu Maps in the Apify Console](#tutorial-scrape-baidu-maps-in-the-apify-console)
- [Tutorial: scrape Baidu Maps with the API](#tutorial-scrape-baidu-maps-with-the-api)
- [Input reference](#input-reference)
- [Output data dictionary (with measured fill rates)](#output-data-dictionary-with-measured-fill-rates)
- [Detail mode: extra fields from each place page](#detail-mode-extra-fields-from-each-place-page)
- [Real output sample](#real-output-sample)
- [How the area splitting works (and why one Baidu search stops at ~200)](#how-the-area-splitting-works-and-why-one-baidu-search-stops-at-200)
- [How much data can I get from Baidu Maps?](#how-much-data-can-i-get-from-baidu-maps)
- [Coordinates: BD-09, GCJ-02 and WGS-84](#coordinates-bd-09-gcj-02-and-wgs-84)
- [Cities, districts, provinces and Baidu city codes](#cities-districts-provinces-and-baidu-city-codes)
- [What you pay](#what-you-pay)
- [Integrations](#integrations)
- [Performance tips](#performance-tips)
- [Troubleshooting: every status message explained](#troubleshooting-every-status-message-explained)
- [Honest limits](#honest-limits)
- [Comparison: Baidu Maps open API, manual copying and this Actor](#comparison-baidu-maps-open-api-manual-copying-and-this-actor)
- [FAQ](#faq)
- [Glossary](#glossary)
- [Is it legal to scrape Baidu Maps?](#is-it-legal-to-scrape-baidu-maps)
- [Changelog](#changelog)
- [Support](#support)

***

### At a glance

| | |
|---|---|
| **What you type** | Keywords in Chinese or English (咖啡, 火锅, 酒店, Starbucks) × cities, districts, counties, provinces, Baidu city codes, admin codes — or a center point + radius, Baidu Maps links, Baidu `uid`s |
| **What you get** | One row per place: `uid`, name, category path, brand, full address + province / city / district / town / street + admin codes, phone (local + E.164), rating, reviews count, price per person (CNY), opening hours (7 days), status, photo, `lat`/`lng` in WGS-84 + GCJ-02 + BD-09 (+ raw BD-09 Mercator x/y), popularity, review tags, recommended dishes, review highlight, Baidu Maps links |
| **Detail mode (optional)** | Description, aliases, postcode, Baidu creation date, detail tags, hotel level / category / facilities / services, nearby landmarks, booking links, sub-ratings (taste, service, environment…), favourites and navigation counts — one extra request per place |
| **Scale** | No ~200-result cap: areas are split into map circles until each circle is complete. Measured: 10,302 Shanghai coffee POIs in one run; 5,854 Dongcheng food POIs; 5,647 Xicheng food POIs; 0 duplicates |
| **Speed** | First rows after ~3 s; 20 places in ~5 s; 1,000 places in ~34 s with defaults |
| **Quality** | Every field checked by hand against the live map.baidu.com mobile and desktop pages on 10+ POIs; de-duplicated by `uid`; coordinates verified on 8 landmarks across mainland China, Hong Kong and Macau (error < 35 m) |
| **Formats** | JSON, CSV, Excel, XML, HTML table, RSS; API, webhooks, Make, Zapier, n8n, Google Sheets |
| **Price** | Pay per place: $3.00 per 1,000 on the Free plan, down to $2.00 per 1,000 on higher Store tiers — compute and requests included |
| **Needs** | Nothing: no Baidu account, no API key (no key / ak / sn), no proxy setup |

***

### What you get: the Baidu Maps data fields

Every place is one flat row. Fields Baidu has no value for are `null` (never an empty string, never a guessed 0). The full dictionary with types and measured fill rates is [further down](#output-data-dictionary-with-measured-fill-rates); this is the overview with real example values from a live Beijing Starbucks row.

#### Identity and links

| Field | Example | |
|---|---|---|
| `uid` | `261d9a8f181b11948c1a894d` | Baidu place id — 24 hex characters; the stable key for refreshes and the `uid=` value in Baidu Maps place links |
| `name` | `星巴克(北京光耀东方店)` | Place name as Baidu shows it (Chinese preserved, HTML stripped) |
| `url` | `https://map.baidu.com/?shareurl=1&poiShareUid=261d9a8f181b11948c1a894d` | Opens the place on Baidu Maps (Baidu's own share-link format) |
| `mobileUrl` | `https://map.baidu.com/mobile/webapp/place/detail/qt=ninf&uid=261d9a8f181b11948c1a894d/vt=map` | The mobile place page this row was read from |

#### Category and brand

| Field | Example |
|---|---|
| `category` | `咖啡厅` (Baidu's leaf category) |
| `categoryTop` | `美食` (Baidu's top-level category: 美食 food, 酒店 hotels, 购物 shopping, 交通 transport…) |
| `categories` | `["美食", "咖啡厅"]` (full path, top → leaf) |
| `tags` | `["美食", "咖啡厅"]` (Baidu's own tags for the place) |
| `brand` | `星巴克` |
| `brandId` | `116` (Baidu's brand id) |

#### Address and admin codes

| Field | Example |
|---|---|
| `address` | `北京市海淀区羊坊店路18号光耀东方广场一层103单元` |
| `fullAddress` | Same, prefixed with province/city/district when Baidu's street line omits them |
| `province` / `provinceCode` | `北京市` / `110000` (6-digit 行政区划代码) |
| `city` / `cityCode` | `北京市` / `110000` |
| `district` / `districtCode` | `海淀区` / `110108` |
| `town` / `townCode` | `羊坊店街道` / `110108003` (street-level office, when Baidu has it) |
| `street` | `羊坊店路` |
| `streetNumber` | `18号` |
| `aoi` | `北京西站/西客站` (the area/landmark Baidu assigns the place to) |
| `parentUid` / `parentName` | `1258856190062886911` / `光耀东方广场` (the mall or building that contains the place) |
| `indoorFloor` | `F1` (mall floor, when Baidu has it) |
| `baiduCityCode` / `baiduAreaCode` | `131` / `1960` (Baidu's own city/area codes — `c=` for Beijing is 131, Haidian is 1960) |

#### Contact

| Field | Example |
|---|---|
| `phone` | `010-63950461` — as Baidu shows it |
| `phones` | `["010-63950461"]` — every number on the listing, split into a list |
| `phoneE164` | `+861063950461` — international format for dialers and CRMs |

#### Rating, price, hours, status

| Field | Example |
|---|---|
| `rating` | `3.5` (Baidu overall rating; `null` when Baidu has none — Baidu's `0` means "no rating") |
| `reviewsCount` | `17` |
| `price` | `49.2` (人均消费 average spend per person) |
| `priceType` | `average per person` (hotels report a per-night price in `hotelPricePerNight` instead) |
| `currency` | `CNY` (`HKD` in Hong Kong, `MOP` in Macau) |
| `openingHours` | `周一至周六 06:00-21:30 周日 06:30-21:30` (rebuilt from Baidu's structured weekly table) |
| `openingHoursWeekly` | `{"monday": "06:00-21:30", … 7 days}` (machine-readable) |
| `openingHoursListed` | `周一至周五07:30-22:00 …` (what the Baidu list card shows; kept when it disagrees) |
| `status` | `open` (`temporarily closed` for Baidu 暂停营业, kept by default) |
| `imageUrl` | Main place photo (`https://poi-pic.cdn.bcebos.com/…`) |

#### Coordinates (three systems at once)

| Field | Example |
|---|---|
| `lat`, `lng` | `39.897918`, `116.315755` — **WGS-84** (GPS / Google Maps outside China / OpenStreetMap) |
| `latGcj02`, `lngGcj02` | `39.899206`, `116.32186` — **GCJ-02** (Amap/Gaode, Tencent, Apple Maps in China) |
| `latBd09`, `lngBd09` | `39.905002`, `116.328431` — **BD-09** (Baidu's own; what you copy from Baidu Maps) |
| `xBd09mc`, `yBd09mc` | `12949762.65`, `4824478.53` — raw BD-09 Mercator meters, Baidu's native grid |
| `hasStreetView` | `true` (Baidu 全景 panorama available) |

#### Popularity and reviews

| Field | Example |
|---|---|
| `popularity` | `1573` (Baidu's internal popularity score) |
| `features` | `["提供在线菜单", "免费停车", "有wifi"]` |
| `reviewTags` | `["高大上", "停车方便", "燕麦拿铁", …]` (review keywords Baidu aggregates) |
| `recommendedDishes` | `["芝士蛋糕", "拿铁", "摩卡星冰乐", …]` (restaurants/food) |
| `reviewHighlight` | `{"text": "…", "date": "2023-03-25 11:09", "source": "百度地图"}` (one featured review) |

#### Search context

| Field | Example |
|---|---|
| `searchTerm` | `咖啡` |
| `searchArea` | `北京市` |
| `rank` | `1` — position in Baidu's own answer for the top-results pass |
| `scrapedAt` | `2026-10-21T19:54:56.784Z` |

***

### Who uses this Baidu Maps scraper

Baidu Maps is the directory Chinese businesses actually maintain — Google Maps has almost no review or hour coverage inside mainland China. These are the teams that turn Baidu POI data into work.

#### 1. China market-entry and expansion teams — "every branch of every competitor"

Search the category (火锅, 咖啡, 药店, 银行) across every prefecture-level city of a province. Each row carries city, district and town with admin codes, so the province roll-up builds itself. Re-run monthly with the same input and diff on `uid` to spot openings and closures.

#### 2. B2B sales and lead generation — phone-verified China lead lists

Pick the verticals you sell to (酒店, 医院, 健身, 学校, 工厂) in the cities you cover, turn on **Only places with a phone number**, and import the CSV into your CRM. Use `uid` as the external id so the next refresh updates instead of duplicating. `phoneE164` dials straight into dialers.

#### 3. Franchise and retail site selection — white-space maps

Pull every POI of the category across a metro (e.g. all 美食 in Dongcheng + Xicheng: ~11,500 rows measured), plot `lat`/`lng` (WGS-84 drops straight into any GIS), and read density gaps against foot-traffic data. `popularity`, `rating` and `reviewsCount` weight each competitor.

#### 4. Food-delivery, logistics and field-service operators — territory planning

A province-wide pull of 超市, 药店 or 加油站 with town-level codes gives you the service-point graph no global map vendor sells. Radius search (`lat`/`lng` + `radiusMeters`) covers "everything within 5 km of this depot".

#### 5. Data teams and data vendors — refreshable China place databases

Baidu `uid`s are stable: store them, then re-run with `uids` (or the same keyword × city input) to refresh rating, reviews, hours, status and coordinates. Admin codes make joins to China's statistical geography trivial.

#### 6. AI and RAG builders — grounded China local knowledge

Feed structured POI rows (name, address, hours, coordinates, review tags) to a travel, relocation or customer-service agent that must answer about places inside China, where Google-sourced knowledge stops.

#### 7. Travel and hospitality platforms — China POI catalogues

Hotels (酒店) with `hotelPricePerNight`, `hotelClass`, `hotelFacilities`, nearby landmarks and booking links; restaurants with price per person, recommended dishes and hours — in Chinese, as Chinese users search it.

#### 8. Real-estate and investment analysts — commercial density studies

Count and grade POIs per district/town (town codes included), track chain penetration by `brand`, and compare commercial mix across cities before a site visit.

#### 9. Compliance, KYC and merchant-verification teams — "does this business exist at this address?"

Look up a merchant by name + city, or directly by `uid` from a Baidu Maps link the merchant sent you. The row returns the Baidu-registered address, admin codes, phone, status and Baidu creation date (detail mode).

#### 10. Academic and public-sector researchers — service-accessibility analysis

Hospitals (医院), schools (学校), banks (银行) and pharmacies (药店) with district/town codes and coordinates — the input for coverage and equity studies across Chinese cities.

#### 11. Overseas Chinese businesses and cross-border e-commerce — supplier and partner discovery

Find manufacturers, wholesalers and distributors by category + industrial city (e.g. 义乌, 广州, 深圳华强北) with phones and addresses, without reading Chinese map UIs yourself.

#### 12. SEO and listing-management agencies — audit Baidu presence

Pull a brand's every branch (brand search: 星巴克, 瑞幸咖啡), compare names, addresses, phones, hours and ratings across cities, and find branches with missing phones or wrong categories.

***

### Cookbook: 16 ready-to-run inputs

Copy any JSON block into **Input** in the Console (or send it to the API). Chinese keywords match best; English brand names work too.

#### 1. One category in one city (the classic)

```json
{ "keywords": ["咖啡"], "cities": ["上海"], "maxItems": 500 }
```

Top Baidu results first, then full circle-splitting coverage of Shanghai. First rows after ~3 s.

#### 2. Every matching place, no limit

```json
{ "keywords": ["美食"], "cities": ["东城区"], "maxItems": 0 }
```

`maxItems: 0` means unlimited. Measured: 5,854 food places in Dongcheng, Beijing, one run. Set **Maximum cost per run** high enough (see [What you pay](#what-you-pay)).

#### 3. A whole province (every city in it)

```json
{ "keywords": ["酒店"], "cities": ["广东省"], "maxItems": 20000 }
```

A province name expands to all its prefecture-level cities automatically. Hainan (18 cities) verified locally.

#### 4. A district or county in Chinese

```json
{ "keywords": ["火锅"], "cities": ["北京市朝阳区"], "maxItems": 2000 }
```

Districts (区), counties (县) and county-level cities (昆山市) resolve with Baidu's own polygon + codes.

#### 5. City by English, pinyin or Baidu code

```json
{ "keywords": ["银行"], "cities": ["Beijing"] }
{ "keywords": ["银行"], "cities": ["beijing"] }
{ "keywords": ["银行"], "cities": ["131"] }
```

北京 / Beijing / beijing / Baidu code 131 / admin code 110000 all mean Beijing. Shared English names pick the bigger city and say so in the log (write 宿州 for Suzhou, Anhui).

#### 6. Several keywords in several cities in one run

```json
{ "keywords": ["咖啡", "奶茶", "面包房"], "cities": ["上海", "杭州", "苏州"], "maxItems": 5000 }
```

Every keyword is searched in every city; `searchTerm` + `searchArea` on each row keep them apart.

#### 7. A circle around a point (lat / lng + radius)

```json
{ "keywords": ["餐厅"], "lat": "39.9087", "lng": "116.3975", "radiusMeters": 5000 }
```

Everything matching inside 5 km of Tiananmen. Radius 50 m–200 km. Set `coordinateSystem` to the system your point is in (`wgs84` default, `gcj02`, or `bd09` for values copied from Baidu Maps).

#### 8. A Baidu Maps search link you already have

```json
{ "startUrls": ["https://map.baidu.com/search/咖啡/@116.40,39.90,13z?wd=咖啡&c=131"] }
```

Search links are re-searched over their visible map area (or the whole city when the link has only a city). Mobile links (`map.baidu.com/mobile/webapp/…`) and short links (`j.map.baidu.com/…`) work too.

#### 9. Look up places you already know (uids, links)

```json
{ "uids": ["261d9a8f181b11948c1a894d"] }
```

Baidu `uid`s (the 24-hex `uid=` value in a place link) return full rows — the cheapest way to refresh a stored list. Place links (`…?uid=…`, `…?poiShareUid=…`) in `startUrls` work the same way.

#### 10. Only well-rated places

```json
{ "keywords": ["火锅"], "cities": ["成都"], "minRating": "4", "maxItems": 1000 }
```

Keeps places rated 4.0+. Places Baidu has no rating for are left out when this is set.

#### 11. Only places with a phone number

```json
{ "keywords": ["酒店"], "cities": ["深圳"], "onlyWithPhone": true, "maxItems": 2000 }
```

The lead-gen filter: ~96–98% of food/coffee rows carry a phone, so this mostly drops the long tail.

#### 12. Only the exact category (drop Baidu's neighbours)

```json
{ "keywords": ["咖啡"], "cities": ["上海"], "categoryFilter": ["咖啡厅"], "maxItems": 2000 }
```

A 咖啡 search mixes in bakeries and tea shops; this keeps rows whose category, tags or name contain 咖啡厅.

#### 13. Skip temporarily closed places

```json
{ "keywords": ["餐厅"], "cities": ["广州"], "skipClosed": true, "maxItems": 2000 }
```

Baidu marks some places 暂停营业. They are kept by default (with `status: "temporarily closed"`); this drops them.

#### 14. Full detail for every place (descriptions, sub-ratings, booking links)

```json
{ "keywords": ["酒店"], "cities": ["杭州"], "maxItems": 200, "includeDetails": true }
```

Opens each place page: description, aliases, postcode, Baidu creation date, hotel facilities/services, nearby landmarks, booking links, sub-ratings. About half speed — one extra request per place.

#### 15. Fastest: Baidu's top results only

```json
{ "keywords": ["咖啡"], "cities": ["北京"], "coverage": "top", "maxItems": 200 }
```

Skips circle-splitting; returns Baidu's own ranking (~100–200 places). The 20-row prefill runs in ~5 s on this path.

#### 16. Monitor new places every week

Run the same keyword × city input on a schedule, store by `uid`, and diff. New `uid`s are openings; `uid`s that now return `status: "temporarily closed"` (or stop resolving) are closures. Nothing in the input needs to change.

***

### Keyword cheat-sheet: what to type for each vertical

Chinese keywords match what Baidu indexes. Copy-paste from this table:

| You want | Type this (Chinese) | Also try |
|---|---|---|
| Coffee shops | 咖啡 / 咖啡厅 | 星巴克, 瑞幸咖啡, 奶茶 |
| Hotpot | 火锅 | 重庆火锅, 海底捞 |
| Restaurants / food | 餐厅 / 美食 | 川菜, 粤菜, 烧烤, 自助餐, 面馆 |
| Hotels | 酒店 | 民宿, 青年旅社, 如家, 汉庭 |
| Banks / ATMs | 银行 | 中国银行, 工商银行, ATM |
| Hospitals / clinics | 医院 / 诊所 | 牙科, 眼科, 体检中心 |
| Pharmacies | 药店 | 同仁堂, 海王星辰 |
| Supermarkets / convenience | 超市 / 便利店 | 沃尔玛, 家乐福, 7-11, 罗森 |
| Gas stations | 加油站 | 中国石化, 中国石油 |
| Gyms / fitness | 健身 / 健身房 | 瑜伽, 游泳馆 |
| Schools / training | 学校 / 培训 | 幼儿园, 大学, 英语培训 |
| Car dealers / repair | 4S店 / 汽车维修 | 洗车, 轮胎 |
| Beauty / hair | 美发 / 美容 | 美甲, SPA |
| Real estate agencies | 房产中介 | 链家, 贝壳 |
| Factories / wholesale | 工厂 / 批发市场 | 服装批发, 电子市场 |
| Tourist spots | 景点 / 公园 | 博物馆, 动物园 |

Brand searches (星巴克, 肯德基, 麦当劳, 瑞幸咖啡, 海底捞, 链家) return every branch with `brand`/`brandId` filled — the fastest chain audit.

### Recipe: weekly refresh and opening/closure diff (Python)

```python
from apify_client import ApifyClient
client = ApifyClient("<TOKEN>")
actor = client.actor("logiover~baidu-maps-scraper")
run = actor.call(run_input={"keywords": ["咖啡"], "cities": ["上海"], "maxItems": 0})
rows = {r["uid"]: r for r in client.dataset(run["defaultDatasetId"]).list_items(clean=True).items}

import json  # previous week, keyed by uid
old = {r["uid"]: r for r in json.load(open("last_week.json"))}
opened = [u for u in rows if u not in old]
closed = [u for u in old if u not in rows]
flipped = [u for u in rows if u in old and rows[u].get("status") != old[u].get("status")]
print(f"total={len(rows)} opened={len(opened)} gone={len(closed)} status_changed={len(flipped)}")
json.dump(list(rows.values()), open("last_week.json", "w"), ensure_ascii=False)
```

### Tutorial: scrape Baidu Maps in the Apify Console

1. Open this Actor and click **Try for free**. The input already contains a working example (咖啡 in 北京, 20 places).
2. Replace the keywords with what you want in Chinese: 火锅 for hotpot, 酒店 for hotels, 药店 for pharmacies. Replace the city with yours: 上海, 深圳, 广州, 成都, 杭州, or a district like 浦东新区.
3. Set **Max places** to how many rows you want (`0` = everything). Leave **Coverage** on *Whole area* unless you only want Baidu's top ~200.
4. Click **Start**. The first rows appear in the **Dataset** tab after ~3 seconds; each row previews live.
5. When the run finishes, open **Dataset**, then **Export** → CSV, Excel or JSON. For recurring pulls, click **Schedule** (top right) — daily or weekly with the same input.

Tip: a broad keyword (美食, 餐厅) over a big city returns tens of thousands of rows. Start with `maxItems: 500` and a district to learn the shape, then scale up.

### Tutorial: scrape Baidu Maps with the API

Run the Actor and fetch the rows (replace `<TOKEN>` with your Apify token, or use OAuth):

```bash
## 1. Start the run (waits up to 60 s and returns the dataset id)
curl -X POST "https://api.apify.com/v2/acts/logiover~baidu-maps-scraper/runs?token=<TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"keywords":["火锅"],"cities":["成都"],"maxItems":1000}'

## 2. Read the rows as JSON (replace <DATASET_ID>)
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&format=json&clean=true"

## 3. Or straight to CSV for a spreadsheet
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&format=csv" -o chengdu-hotpot.csv
```

Python (with `apify-client`: `pip install apify-client`):

```python
from apify_client import ApifyClient
client = ApifyClient("<TOKEN>")
run = client.actor("logiover~baidu-maps-scraper").call(
    run_input={"keywords": ["咖啡"], "cities": ["上海"], "maxItems": 1000}
)
rows = client.dataset(run["defaultDatasetId"]).list_items(clean=True).items
print(len(rows), rows[0]["name"], rows[0]["phone"], rows[0]["lat"], rows[0]["lng"])
```

***

### Input reference

| Field | Type | Default | What it does |
|---|---|---|---|
| `keywords` | string list | `[]` (prefill 咖啡) | What to search, as typed into Baidu Maps. Chinese matches best; English brands work. Each keyword runs in every city/area. |
| `cities` | string list | `[]` (prefill 北京) | City (北京 / Beijing / beijing), Baidu code (`131`), admin code (`110000`), district/county (海淀区, 北京市朝阳区, 浦东新区, 昆山市), province (广东省 = every city in it). |
| `maxItems` | integer | `1000` (prefill 20) | Stop after this many unique places. `0` = no limit. Big runs need a matching **Maximum cost per run**. |
| `coverage` | `full` / `top` | `full` | `full`: top results + circle-splitting (everything). `top`: Baidu's own ranking only (~100–200, fastest). |
| `includeDetails` | boolean | `false` | Open every place page for description, aliases, postcode, creation date, hotel data, booking links, sub-ratings. ~2× requests. |
| `lat` / `lng` | strings | — | Circle centre (e.g. `39.9087` / `116.3975`). Used with `radiusMeters` + `coordinateSystem`. Works alone or with `cities`. |
| `radiusMeters` | integer | `1000` | Circle radius, 50 m–200 km. Every matching place inside is returned (split as needed). |
| `coordinateSystem` | `wgs84` / `gcj02` / `bd09` | `wgs84` | The system your `lat`/`lng` point is in. `bd09` for values copied from Baidu Maps. |
| `uids` | string list | `[]` | Baidu place ids (24 hex chars) to look up directly. Cheapest refresh path. |
| `startUrls` | URL list | `[]` | Baidu Maps links: place links (`?uid=`, `?poiShareUid=`) are looked up; search links re-run their map area; mobile + short links supported. |
| `maxItemsPerSearch` | integer | `0` | Cap per keyword × area. `0` = no per-search cap. |
| `categoryFilter` | string list | `[]` | Keep rows whose category, tags or name contain one of these words (e.g. 咖啡厅). |
| `minRating` | `""` / `3` / `3.5` / `4` / `4.5` | `""` | Minimum Baidu rating. Unrated places are excluded when set. |
| `onlyWithPhone` | boolean | `false` | Drop places without a phone number. |
| `skipClosed` | boolean | `false` | Drop 暂停营业 (temporarily closed) places. |
| `proxyConfiguration` | proxy object | Apify Proxy on | Fallback only: the scraper reads Baidu over a direct connection and Apify datacenter proxies side by side at no proxy cost to you; your setting takes over only if both are refused. |

***

### Output data dictionary (with measured fill rates)

Types are JSON types. Fill rates were measured on two platform runs: 咖啡 in 上海 (10,302 rows, sampled 50) and 火锅 in 成都 (1,000 rows, sampled 50) — food/coffee rows. Hotel, hospital and bank searches fill `hotelPricePerNight`/`hotelClass` and phone fields at their own rates; `null` always means "Baidu has no value".

| Field | Type | Fill (coffee/food) | Notes |
|---|---|---|---|
| `uid` | string | 100% | 24 hex chars, e.g. `261d9a8f181b11948c1a894d`. De-dupe key. |
| `name` | string | 100% | Chinese preserved, HTML stripped. |
| `category` | string | 100% | Leaf category, e.g. 咖啡厅, 火锅店. |
| `categoryTop` | string | 100% | Top category: 美食, 酒店, 购物, 生活服务… |
| `categories` | string\[] | 100% | Full path top → leaf. |
| `tags` | string\[] | 100% | Baidu's own tags. |
| `brand` / `brandId` | string | 78–82% | Chains only (星巴克 + id `116`). Independent shops: `null`. |
| `address` / `fullAddress` | string | 100% | `fullAddress` adds province/city/district prefix when Baidu's line omits it. |
| `province` / `provinceCode` | string | 100% | e.g. 北京市 / `110000`. |
| `city` / `cityCode` | string | 100% | 6-digit admin code. |
| `district` / `districtCode` | string | 100% | e.g. 海淀区 / `110108`. |
| `town` / `townCode` | string | 100% (names), 100% (codes) | Street office (街道), e.g. 羊坊店街道 / `110108003`. |
| `street` | string | 98% | e.g. 羊坊店路. |
| `streetNumber` | string | 16–34% | e.g. `18号`. Baidu often omits it. |
| `aoi` | string | 92–98% | Area/landmark, e.g. 北京西站/西客站. |
| `parentUid` / `parentName` | string | 50–74% / 6–8% | Mall/building container; name only when Baidu names it (光耀东方广场). |
| `indoorFloor` | string | 0–30% | Mall floor (`F1`, `B1`); category-dependent. |
| `baiduCityCode` / `baiduAreaCode` | integer | 100% | Baidu's own codes (Beijing 131, Haidian 1960). |
| `phone` / `phones` / `phoneE164` | string / string\[] / string | 96–98% | Split into a list; E.164 for dialers (`+861063950461`). |
| `rating` | number | 100% (as `null` when none) | `null` = Baidu has no rating (Baidu `0` normalized). |
| `reviewsCount` | integer | 100% (as `null` when none) | Baidu 评论数. |
| `price` | number | 100% (as `null` when none) | 人均消费 CNY per person, e.g. `49.2`. |
| `priceType` | string | 100% with price | `average per person`. |
| `currency` | string | 100% with price | `CNY` (`HKD`/`MOP` in HK/Macau). |
| `hotelPricePerNight` | number | 0% (food) | Hotels only (Baidu hotelpc feed). |
| `hotelClass` | string | 0% (food) | Hotels only (list + detail level). |
| `openingHours` | string | 94–100% | Rebuilt from Baidu's structured weekly table. |
| `openingHoursWeekly` | object | 100% | `monday…sunday`, e.g. `06:00-21:30`. |
| `openingHoursListed` | string | 74–80% | What the Baidu list card shows (older feed; kept on disagreement). |
| `openingHoursUpdatedAt` | string (ISO) | 100% | When Baidu updated the hours. |
| `status` / `statusCode` | string / integer | 100% | `open` (1) or `temporarily closed` (3, 暂停营业). |
| `statusNote` | string | 0% | Rare Baidu gray-line note; `null` otherwise. |
| `imageUrl` | string | 100% (food/coffee) | `poi-pic.cdn.bcebos.com` photo. Icon placeholders filtered out. |
| `lat` / `lng` | number | 100% | WGS-84. |
| `latGcj02` / `lngGcj02` | number | 100% | GCJ-02. |
| `latBd09` / `lngBd09` | number | 100% | BD-09. |
| `xBd09mc` / `yBd09mc` | number | 100% | Raw BD-09 Mercator meters. |
| `hasStreetView` | boolean | 100% | Baidu 全景 panorama flag. |
| `popularity` | number | 0–68% | Baidu internal score; varies by category backend. |
| `features` | string\[] | 46–52% | e.g. 提供在线菜单, 免费停车, 有wifi. |
| `reviewTags` | string\[] | 66–74% | Aggregated review keywords. |
| `recommendedDishes` | string\[] | 42–44% | Food rows. |
| `reviewHighlight` | `{text,date,source}` | 100% (object, text may vary) | One featured review with date + source. |
| `url` / `mobileUrl` | string | 100% | Share link + mobile place page. |
| `searchTerm` / `searchArea` / `rank` / `scrapedAt` | string / string / int / string | 100% | Provenance for every row. |

### Detail mode: extra fields from each place page

`includeDetails: true` opens every place's Baidu page (`qt=ninf`) and adds these fields. Verified on live detail payloads; one extra request per place (~half speed).

| Field | Type | Notes |
|---|---|---|
| `description` | string | Long description (rich_info / base), Chinese. |
| `alias` | string\[] | Alternate names, split on `|`/`$`, excluding the main name. |
| `postcode` | string | e.g. `100038`. |
| `createdAt` | string (ISO) | The date Baidu created the place record. |
| `detailTags` | string\[] | `detail_info.tag` split. |
| `hotelCategory` | string | Hotel category (rich_info). |
| `hotelFacilities` / `hotelServices` | string | e.g. inner/hotel facility + service texts. |
| `nearbyLandmarks` | string | Surroundings (`environment_exterior`). |
| `reservationLinks` | `{source,url}[]` | Booking/reservation links with source labels. |
| `subRatings` | object | `taste/service/environment/facility/hygiene/location` (only dimensions Baidu rates). |
| `favoritesCount` / `navigationCount` | integer | Baidu 收藏 / 导航 counts. |
| `shopHoursDetail` | string | rich_info shop hours text (third hours source, kept raw). |

***

### Real output sample

One real row from the platform run 咖啡 in 北京 (20 places, prefill): a Starbucks in Haidian, exactly as the dataset returns it (review-tag list trimmed for length — the live row carries all 30+ tags).

```json
{
  "uid": "261d9a8f181b11948c1a894d",
  "name": "星巴克(北京光耀东方店)",
  "category": "咖啡厅",
  "categoryTop": "美食",
  "categories": ["美食", "咖啡厅"],
  "tags": ["美食", "咖啡厅"],
  "brand": "星巴克",
  "brandId": "116",
  "address": "北京市海淀区羊坊店路18号光耀东方广场一层103单元",
  "fullAddress": "北京市海淀区羊坊店路18号光耀东方广场一层103单元",
  "province": "北京市",
  "provinceCode": "110000",
  "city": "北京市",
  "cityCode": "110000",
  "district": "海淀区",
  "districtCode": "110108",
  "town": "羊坊店街道",
  "townCode": "110108003",
  "street": "羊坊店路",
  "streetNumber": "18号",
  "aoi": "北京西站/西客站",
  "parentUid": "1258856190062886911",
  "parentName": "光耀东方广场",
  "indoorFloor": "F1",
  "baiduCityCode": 131,
  "baiduAreaCode": 1960,
  "phone": "010-63950461",
  "phones": ["010-63950461"],
  "phoneE164": "+861063950461",
  "rating": 3.5,
  "reviewsCount": 17,
  "price": 49.2,
  "priceType": "average per person",
  "currency": "CNY",
  "hotelPricePerNight": null,
  "hotelClass": null,
  "openingHours": "周一至周六 06:00-21:30 周日 06:30-21:30",
  "openingHoursWeekly": {
    "monday": "06:00-21:30",
    "tuesday": "06:00-21:30",
    "wednesday": "06:00-21:30",
    "thursday": "06:00-21:30",
    "friday": "06:00-21:30",
    "saturday": "06:00-21:30",
    "sunday": "06:30-21:30"
  },
  "openingHoursListed": "周一至周五07:30-22:00 周六至周日09:00-22:00",
  "openingHoursUpdatedAt": "2026-09-08T02:17:00.000Z",
  "status": "open",
  "statusCode": 1,
  "statusNote": null,
  "imageUrl": "https://poi-pic.cdn.bcebos.com/swd/28a1b2ce-de00-3b51-afb7-d02a1beaca28.jpg",
  "lat": 39.897918,
  "lng": 116.315755,
  "latGcj02": 39.899206,
  "lngGcj02": 116.32186,
  "latBd09": 39.905002,
  "lngBd09": 116.328431,
  "xBd09mc": 12949762.65,
  "yBd09mc": 4824478.53,
  "hasStreetView": true,
  "popularity": 1573,
  "features": ["提供在线菜单", "免费停车", "有wifi"],
  "reviewTags": ["高大上", "停车方便", "朋友小聚", "环境优雅", "燕麦拿铁", "冰美式", "服务热情", "干净卫生"],
  "recommendedDishes": ["芝士蛋糕", "拿铁", "摩卡星冰乐", "焦糖玛奇朵", "抹茶拿铁", "三明治"],
  "reviewHighlight": {
    "text": "在楼下的咖啡店，买了一杯冰的冷翠咖啡，味道不错，小程序很方便，店员小姐姐很热情",
    "date": "2023-03-25 11:09",
    "source": "百度地图"
  },
  "url": "https://map.baidu.com/?shareurl=1&poiShareUid=261d9a8f181b11948c1a894d",
  "mobileUrl": "https://map.baidu.com/mobile/webapp/place/detail/qt=ninf&uid=261d9a8f181b11948c1a894d/vt=map",
  "searchTerm": "咖啡",
  "searchArea": "北京市",
  "rank": 1,
  "scrapedAt": "2026-10-21T19:54:56.784Z"
}
```

Hand-checked against the live map.baidu.com mobile and desktop pages: name, address, phone, rating, hours and coordinates match the listing Baidu shows.

***

### How the area splitting works (and why one Baidu search stops at ~200)

A single Baidu mobile search (`qt=s&c=<city>`) returns Baidu's own top results — 100 to ~200 places depending on keyword and city (191 for 咖啡 in Beijing, 103 for 学校 in Nanjing). That is Baidu's ranking, not the whole city: a big city holds tens of thousands of restaurants. The Actor therefore works in two passes.

**Pass 1 — Baidu's top results.** The city search runs first with distance sorting (`pl_sort_type=distance`), which paginates stably (101/101 unique pages measured; Baidu's default ranking duplicates rows across pages, e.g. only 82 unique of 103). Every row is kept with its `rank`.

**Pass 2 — circle splitting.** The area (city polygon from Baidu's own admin answer, district, province → its cities, or your radius circle) is covered with nearby-search circles (`qt=nb` with `nb_x/nb_y` in BD-09 Mercator plus `pl_dist=0,<metres>`, which constrains results strictly inside the circle — verified by distance). Each circle answers completely **below its cap**: the union of 9 sub-circles equals the parent circle (coffee 31=31, banks 50=50, schools 101≈102, food 122≈123). But a circle **at its cap is not trustworthy** — a 20 km and a 50 km radius circle can both return 145 gas stations with different sets, so capped circles are never accepted as complete. Any circle that hits its cap (70–197 depending on keyword and place density: banks 70–81, hotels 76–103, schools 107–111, food 159–196, gas 125–145) is split into smaller circles until every circle answers below its cap. Splitting stops at 30 results per circle by default (`SPLIT_AT 30` — tested T=20/30/60/100; 30 gives the same places as 60 for ~35% more requests, completeness first).

Results are de-duplicated by `uid` across all circles, searches and keywords, so the run in [How much data](#how-much-data-can-i-get-from-baidu-maps) reports 0 duplicates at every scale. Rows outside the requested Baidu city code are filtered out (Baidu sometimes answers a far-away city for airport-like queries — e.g. 机场 in 定安县 returns Chengdu airports); those answers are treated as empty for that area rather than as results.

The desktop web search (`map.baidu.com/?newmap=1&qt=s`) is deliberately **not** used: it answers `need_recaptcha` on direct, datacenter and residential proxies — even inside a real Chrome. The mobile webapp endpoint works 3/3 on direct, datacenter and residential routes with no captcha at ~0.6 MB HTML per page of 10 POIs. Detail pages (`qt=ninf`, ~185 KB) power `uid` lookups and detail mode; the suggestion endpoint (`map.baidu.com/su`) resolves city names.

### How much data can I get from Baidu Maps?

Measured on the Apify platform (October 2026), defaults unless noted:

| Run | Rows | Time | Requests | Refused | Notes |
|---|---|---|---|---|---|
| 咖啡 in 北京, 20 places (prefill) | 20 | 5.6 s | 2 | 0 | first rows ~3 s |
| 火锅 in 成都, 1,000 places (defaults) | 1,000 | 33.8 s | 139 | 0 | ~30 rows/s |
| 咖啡 in 上海, everything | 10,302 | 423.5 s | — | 0 | one run, 0 duplicates |
| 美食 in 东城区 (Beijing), everything | 5,854 | ~195 s | 2,332 | 0 | SPLIT_AT 30 |
| 美食 in 西城区 (Beijing), everything | 5,647 | 167 s | 2,183 | 0 | direct p50 ~0.5 s at ~7 rps |

Locally: 海南 province (18 cities) resolves and runs; county-level cities (昆山), districts (海淀区) and cross-boundary circles (Beijing/Langfang → one search per city) verified. A 0-page run never reports success — empty answers fail loudly instead of charging for nothing.

### Coordinates: BD-09, GCJ-02 and WGS-84

China maps use three systems and they disagree by hundreds of meters, so every row carries all three plus the raw grid:

- **BD-09** is Baidu's own (what you copy from map.baidu.com). The Actor reads Baidu's native BD-09 Mercator meters (`x`/`y` ×100) and converts standard-formula to BD-09 lat/lng.
- **GCJ-02** ("Mars coordinates") is what Amap/Gaode, Tencent Maps and Apple Maps show inside China — the Actor converts BD-09 → GCJ-02 so rows overlay correctly there.
- **WGS-84** is GPS / Google Maps / OpenStreetMap. The Actor converts GCJ-02 → WGS-84, so `lat`/`lng` drop straight into any GIS, PostGIS, BigQuery GIS or map SDK outside the Baidu world.

Verified on 8 landmarks (OSM WGS-84 vs converted): Oriental Pearl 10.9 m, Canton Tower 13.6 m, Big Wild Goose Pagoda 5.8 m, Yellow Crane Tower 14.5 m, Monument to the People's Heroes 8.3 m, HK Clock Tower 8.2 m, Macau Tower 7.4 m, Shanghai Tower 34 m (large-building footprint). Baidu applies the GCJ offset in Hong Kong, Macau and Taiwan too — conversion handles that.

If your input point comes from Baidu Maps itself, set `coordinateSystem: "bd09"`; from Amap/Tencent/Apple-in-China use `gcj02`; from GPS/Google use `wgs84` (default). Wrong system = your circle lands ~500 m off.

### Cities, districts, provinces and Baidu city codes

- 362 Baidu cities ship in the Actor (from Baidu's own mobile city picker) with pinyin: `Beijing`, `beijing`, 北京, Baidu code `131` and admin code `110000` all resolve to Beijing.
- 5 pinyin collisions resolve to the bigger city with a log warning (Suzhou, Taizhou, Fuzhou, Yichun, Yulin) — write 宿州 for Suzhou (Anhui).
- Districts and counties carry Baidu's own boundary polygon + admin codes (海淀区 → area 1960, polygon from `guoke_geo`); Hong Kong (2912) and Macau (2911) have no polygon in Baidu's backend and use its other search path, handled automatically.
- A province name (广东省, Hainan) expands to all its prefecture-level cities; a nearby circle crossing a city border fans out to one search per city.

***

### What you pay

Pay per place (one dataset item = one place). Store tier discounts apply automatically — higher tiers pay less, down to a floor:

| Tier | FREE | BRONZE | SILVER | GOLD | PLATINUM | DIAMOND |
|---|---|---|---|---|---|---|
| Per 1,000 places | $3.00 | $2.67 | $2.33 | $2.00 | $2.00 | $2.00 |

Compute, requests and detail-page reads are included — the price is per saved row, not per request. 1,000 Chengdu hotpot places cost ~$3.00 on the Free plan (platform usage measured $0.0046 in compute on top of the per-result price is already inside it — you pay the per-result price only). `uid` lookups and detail mode cost the same per row.

#### Maximum cost per run

**Maximum cost per run** caps what one run can spend. The Actor converts it into a row budget at the current price and stops cleanly when it is reached (`stoppedBy: "MAX_COST"` in the output) — it never spends more. Rule of thumb:

- Sampling (`maxItems: 500`): $2 covers it on any tier.
- 1,000 places: $3 on Free, $2 on Gold+.
- Whole-city broad keywords (美食 in Shanghai/Beijing, 10k+ rows): $25–35.
- Whole-province pulls: set $50+ and `maxItems: 0`, then watch the first 1,000 rows and scale.

If the cap covers fewer rows than `maxItems`, the run saves what the cap covers and tells you exactly that in the status message — raise the cap to get the rest.

#### Cost estimator (measured pulls)

| Pull | Rows | Free ($3/1k) | Gold+ ($2/1k) |
|---|---|---|---|
| Sample (`maxItems: 500`) | 500 | $1.50 | $1.00 |
| Chengdu hotpot (defaults) | 1,000 | $3.00 | $2.00 |
| Dongcheng food, everything | 5,854 | $17.56 | $11.71 |
| Xicheng food, everything | 5,647 | $16.94 | $11.29 |
| Shanghai coffee, everything | 10,302 | $30.91 | $20.60 |
| Province-wide broad keyword | 50,000 | $150.00 | $100.00 |

***

### Integrations

- **Google Sheets**: Actor → *Export to Google Sheets* (built-in integration), or schedule runs and `IMPORTDATA` the CSV export URL.
- **Make / Zapier / n8n**: use the Apify modules — *Run Actor* with the JSON from the [Cookbook](#cookbook-16-ready-to-run-inputs), then iterate over dataset items.
- **Webhooks**: add a webhook on run success that POSTs the dataset URL to your endpoint; rows arrive as JSON.
- **API + datasets**: every run lands in its default dataset — JSON, CSV, Excel, XML, HTML or RSS via the dataset-items endpoints (see the [API tutorial](#tutorial-scrape-baidu-maps-with-the-api)).
- **CRM / database**: upsert on `uid` (stable across runs). Admin codes (`provinceCode/cityCode/districtCode/townCode`) join to China statistical geography; WGS-84 `lat`/`lng` load into PostGIS/BigQuery GIS without conversion.

***

### Performance tips

- Start small: `maxItems: 500` + one district teaches you the category's density before you pay for a province.
- `coverage: "top"` is 10–20× faster when Baidu's own ~200 is enough (brand audits, quick samples).
- `includeDetails: true` roughly halves speed — use it on ≤1,000-row pulls, or run broad without details and re-fetch the winners by `uids` with details on.
- Broad keywords (美食, 餐厅) over big cities are the slowest pulls (10k+ rows, ~7 min). Narrow keywords (加油站, 银行) finish in 1–2 minutes per city.
- `categoryFilter` and `minRating` filter after collection — they don't speed up the run, but `maxItemsPerSearch` stops a dense city from eating the whole `maxItems` budget.
- Radius searches are fastest for small areas: a 1 km circle returns in seconds.

***

### Troubleshooting: every status message explained

| Message | Meaning | What to do |
|---|---|---|
| `Saved N places in S s.` | Full success — every area answered below its cap. | Export the dataset. |
| `Saved N places (max results reached) in S s.` | `maxItems` hit; more places exist. | Raise `maxItems` (and cost cap) for the rest. |
| `Saved N places — this run's maximum cost covers M results…` | Cost cap hit (`stoppedBy: "MAX_COST"`). | Raise **Maximum cost per run**. |
| `Saved 0 places — the maximum cost does not cover a single result.` | Cap below one row's price. | Raise the cap above ~$0.01. |
| City resolved to the bigger namesake | Pinyin/English collision (Suzhou, Taizhou…). | Use the Chinese name (宿州) — the log names what was picked. |
| Fewer rows than expected with `categoryFilter`/`minRating`/`onlyWithPhone`/`skipClosed` | Filters drop rows after collection. | Loosen the filters; check counts without them first. |
| Run fails with no pages read | Baidu refused every route (rare; mobile endpoint measured 3/3). | Retry — the run fails loudly and never reports empty success. |

***

### Honest limits

- Baidu's data is only as fresh as Baidu: hours, phones and 暂停营业 flags are what the listing shows; the Actor reports them, it doesn't verify by calling.
- `streetNumber` is missing on ~70–85% of rows, `parentName` on ~90%+: Baidu often doesn't have them. `null` means absent, not zero.
- `openingHours` and `openingHoursListed` can disagree (structured weekly table vs older list-card feed) — both are kept so you can see it.
- `popularity` is absent on some category backends (0% on the Chengdu hotpot sample, 68% on Shanghai coffee).
- Review **texts** are one highlight per place, not full paginated reviews — Baidu's review stream is a separate product.
- Hong Kong/Macau rows convert coordinates the same way (error < 10 m measured) but Baidu serves them from a different backend without district polygons.
- Big runs take minutes (10k rows ≈ 7 min) — this is complete data, not a sample; schedule accordingly.

***

### Comparison: Baidu Maps open API, manual copying and this Actor

| | Baidu Maps open API (lbsyun) | Manual copying from map.baidu.com | This Actor |
|---|---|---|---|
| Needs | Developer account, key/ak + sn signature, quota application | Nothing but patience | Nothing (no key, no login) |
| Coverage | Quota-limited, per-key rate limits, place search caps | Whatever you can click (~10/page, one page at a time) | Whole cities/provinces, 10k+ rows/run, 0 duplicates |
| Fields | What the API exposes (no review tags, no weekly hours table) | What you see (one place at a time) | 60+ fields incl. all three coordinate systems, admin codes, review tags, dishes, sub-ratings |
| Coordinates | BD-09 or GCJ-02 only (you convert) | BD-09 (copied from the page) | WGS-84 + GCJ-02 + BD-09 + raw Mercator |
| Cost model | Per-request quotas, overage billing | Your time | $3 → $2 per 1,000 places |
| Refresh | Re-query everything | Re-click everything | Re-run by `uid`s; diff on `uid` |

The only Store alternative (zen-studio's baidu-maps-scraper, $3.99/1k, ~21 users/30d) costs more per row and publishes fewer fields (no triple coordinates, no admin-code chain, no detail mode).

***

### FAQ

#### What is a Baidu Maps scraper?

A tool that reads Baidu Maps (百度地图) place listings at scale and returns them as structured rows — name, address, phone, category, rating, hours, coordinates — instead of one page at a time in a browser.

#### How do I scrape Baidu Maps without an API key?

Use this Actor: type keywords + cities, start the run. It reads Baidu's mobile webapp endpoints directly — no Baidu developer account, no key/ak/sn, no quota application.

#### Is this a Baidu Maps API alternative?

Yes, for place-data use cases (POI export, lead lists, market mapping). It needs no credentials and returns review/field coverage the lbsyun API doesn't expose (review tags, weekly hours table, triple coordinates, admin-code chain).

#### Which keywords work best — Chinese or English?

Chinese: 咖啡 beats "coffee", 火锅 beats "hotpot". English brand names (Starbucks, Luckin, KFC) work. When in doubt, copy the word from map.baidu.com's own search box.

#### How many results can I get from Baidu Maps?

One Baidu search shows ~100–200. This Actor removes that cap by splitting areas into circles: 10,302 Shanghai coffee POIs in one measured run, ~11,500 food POIs across two Beijing districts.

#### Why does Baidu Maps only show ~200 results?

Baidu returns its own ranked top results per search, not the whole index. Same pattern as Google Maps' 120-cap — solved the same way, by re-searching smaller areas until each answers completely.

#### How do I scrape all businesses in a city?

Keyword + city with `maxItems: 0` and `coverage: "full"`. For a huge city and a broad keyword, expect 10k+ rows and set the cost cap accordingly ($25–35).

#### Can I scrape a whole province?

Yes — write the province (广东省, 海南省, 四川省) in `cities`; it expands to all prefecture-level cities automatically.

#### How do I search by Baidu city code?

Put the code in `cities`: `"131"` for Beijing. Admin codes (`110000`) work too, as do pinyin and English names.

#### What are Baidu city codes (131, 2912)?

Baidu's own numbering: Beijing 131, Shanghai 289, Guangzhou 257, Shenzhen 340, Hong Kong 2912, Macau 2911. You rarely need them — Chinese/English names resolve the same way — but `baiduCityCode`/`baiduAreaCode` on every row let you verify routing.

#### How do I search near coordinates?

Set `lat`, `lng` (as strings) + `radiusMeters` (50–200,000). Tell it which system your point is in via `coordinateSystem`. Works alone or together with `cities`.

#### My point is copied from Baidu Maps. Which coordinate system?

`bd09`. From Amap/Gaode, Tencent or Apple-in-China: `gcj02`. From GPS or Google Maps: `wgs84` (the default).

#### Can I paste Baidu Maps URLs?

Yes: place links (`?uid=`, `?poiShareUid=`) are looked up; search links re-run their map area; mobile webapp and `j.map.baidu.com` short links work.

#### Can I look up a list of place ids?

Yes — `uids` takes Baidu `uid`s (24 hex chars) and returns full rows. The cheapest refresh path for a stored database.

#### How do I extract phone numbers from Baidu Maps?

Every row carries `phone`, `phones[]` and `phoneE164`. Add `"onlyWithPhone": true` to drop the ~2–4% of rows without one.

#### What format are the coordinates in?

All three at once: `lat`/`lng` = WGS-84 decimal degrees (GPS standard), `latGcj02`/`lngGcj02` = GCJ-02, `latBd09`/`lngBd09` = BD-09, plus raw `xBd09mc`/`yBd09mc` Mercator meters. Verified < 35 m on 8 landmarks.

#### How do I get only one exact category?

`categoryFilter: ["咖啡厅"]` keeps rows whose category, tags or name contain it — drops the bakeries Baidu mixes into a 咖啡 search.

#### Does it return opening hours?

Yes: `openingHours` text + machine-readable `openingHoursWeekly` (7 days) + Baidu's list-card text + update timestamp. ~94–100% fill on food/coffee.

#### Does it get ratings and review counts?

Yes — `rating`, `reviewsCount`, plus `reviewTags`, `recommendedDishes` and one `reviewHighlight` with date. Baidu "no rating" arrives as `null`, not 0.

#### Does it get prices?

Yes — `price` (人均消费 per person, CNY) on food rows; hotels report `hotelPricePerNight` + `hotelClass` instead.

#### Can I export Baidu Maps data to Excel or CSV?

Yes — the dataset exports to CSV, Excel, JSON, XML, HTML and RSS from the Console, or via the dataset API endpoints.

#### How fast is it?

\~3 s to first rows; 20 rows ~5 s; 1,000 rows ~34 s; 10,000+ rows ~7 min with full circle-splitting. Detail mode roughly halves speed.

#### How much does it cost?

$3.00 per 1,000 places on the Free plan down to $2.00 on higher tiers. 500 sample rows ≈ $1.50; a 10k-row city pull ≈ $20–30. The cost cap guarantees a run never overspends.

#### Do I need proxies?

No. The Actor reads Baidu over direct + datacenter routes side by side at no proxy cost; your `proxyConfiguration` is a fallback Baidu has not needed in testing (0 refused requests on measured platform runs).

#### Do I need a Baidu account or cookies?

No.

#### Will I get duplicates?

No — de-duplicated by `uid` across circles, searches and keywords (0 duplicates at every measured scale).

#### Are temporarily closed places included?

Yes, with `status: "temporarily closed"`, unless `skipClosed: true` drops them.

#### Why are some places outside my city?

Baidu occasionally answers a far-away city for airport-like queries. Rows outside the requested Baidu city code are filtered automatically.

#### Why did my run return fewer places than Max places?

Either Baidu genuinely has fewer (narrow keyword, small town — success, not failure), or filters (`categoryFilter`, `minRating`, `onlyWithPhone`, `skipClosed`) dropped rows. The status message tells you which limit stopped the run.

#### Does it work for Hong Kong, Macau and Taiwan?

Yes — coordinates convert the same way (HK Clock Tower 8.2 m, Macau Tower 7.4 m measured). HK/Macau route through Baidu's other backend automatically; district polygons don't exist there, so coverage falls back to city + circles.

#### Can I monitor new businesses?

Yes — schedule the same input weekly, key on `uid`, diff for openings/closures/status flips.

#### Can AI agents use this scraper?

Yes — flat JSON rows with stable `uid`s, ISO timestamps, triple coordinates and provenance fields (`searchTerm`, `searchArea`, `rank`, `scrapedAt`) are built for RAG and tool-calling agents.

#### Is there a free trial?

Apify's free tier includes platform usage to try the Actor; per-result pricing applies to saved rows per the tier table above.

#### What happens if Baidu blocks the run?

Measured refusal rate is zero (mobile endpoint 3/3 on all route types). If every route were refused, the run fails loudly — a 0-page run never reports success, and uncharged-for rows cost nothing.

#### I need a field or filter that is missing. Can you add it?

Ask via the Store support channel (see [Support](#support)) with the Baidu page that shows the field — Baidu exposes ~110 fields per POI and most can be mapped.

#### Does it scrape full Baidu review texts?

It returns one featured `reviewHighlight` plus aggregated `reviewTags` and `recommendedDishes` per place — enough for rating, dish and sentiment analysis. Full paginated review streams (every review text) are a separate product; ask via [Support](#support) if you need them.

#### Can I filter to one district inside a city run?

Yes — put the district in `cities` (海淀区, 浦东新区) instead of the city. Each `cities` entry runs independently, so `["海淀区", "朝阳区"]` with `maxItemsPerSearch: 2000` gives you per-district caps in one run.

#### What do `qt=nb`, `pl_dist` and `pn` mean?

Baidu mobile endpoint parameters the Actor manages for you: `qt=s` keyword search, `qt=nb` nearby-circle search with `pl_dist=0,<metres>` constraining results strictly inside the circle, `qt=ninf` place detail, `pn` page number (10 rows/page, `rn` can't be raised). You never set these — they're documented here so the [splitting method](#how-the-area-splitting-works-and-why-one-baidu-search-stops-at-200) is auditable.

#### 百度地图数据怎么导出？(How do I export Baidu Maps data?)

用这个 Actor：输入关键词（如 咖啡、火锅）+ 城市（如 上海、北京），运行后在 Dataset 里导出 CSV / Excel / JSON。支持百度地图 POI 数据采集、电话提取、坐标导出（WGS-84/GCJ-02/BD-09）、区县和行政区划代码。

***

### Glossary

| Term | Meaning |
|---|---|
| `uid` | Baidu place id (24 hex chars) — the stable key for a place. |
| BD-09 | Baidu's coordinate system (what map.baidu.com shows). |
| GCJ-02 | China's "Mars" system — Amap/Gaode, Tencent, Apple in China. |
| WGS-84 | GPS standard — Google Maps outside China, OpenStreetMap, all GIS. |
| BD-09MC x/y | Baidu's native Mercator meters (÷100 from Baidu's raw values). |
| Baidu city code (`c=`) | Baidu's city number (Beijing 131, Shanghai 289…). |
| Admin code | China's 6-digit 行政区划代码 (Beijing 110000, Haidian 110108). |
| `qt=s` / `qt=nb` / `qt=ninf` | Baidu mobile endpoints: keyword search / nearby-circle search / place detail. |
| `pn` / `rn` | Baidu pagination: page number / rows per page (fixed 10). |
| 人均消费 | Average spend per person (CNY) — the `price` field. |
| 暂停营业 | Temporarily closed — the `status` value Baidu assigns. |
| AOI | Baidu's area/landmark label for a place (e.g. a station district). |
| SPLIT_AT | Circle-split threshold (30 results): fuller circles split further. |
| MAX_COST | Your **Maximum cost per run**, converted to a row budget. |

***

### Is it legal to scrape Baidu Maps?

Public business listings (names, addresses, phones businesses publish to attract customers, ratings, hours) are widely scraped for lead generation, mapping and research. That said: respect Baidu's Terms of Service, applicable laws (including China's data and personal-information rules for any personal data), and robots/rate guidance; don't republish Baidu content verbatim (photos, review texts) as your own; and use the data for legitimate business purposes (leads, analytics, mapping) rather than spam or harassment. This Actor collects only what Baidu's public place pages show, at a polite request rate, and is not affiliated with Baidu. This is general information, not legal advice.

***

### Changelog

- **1.0.2** (2026-10-21): share-link `url` format (Baidu's own `poiShareUid` links); `openingHours` rebuilt from the structured weekly table.
- **1.0.1** (2026-10-21): production release — mobile-webapp route, circle splitting, triple coordinates, admin-code chain, `uid` lookups, detail mode, pay-per-result pricing.
- **1.0.0** (2026-10-21): initial build.

***

### Support

Found a place the Actor reads wrong, a city name that doesn't resolve, or a field you need? Open a discussion on the Actor's Store page with the keyword + city + (ideally) the Baidu Maps link of the place. Include the run id — every row's `scrapedAt` and every run's input make bugs reproducible in one glance. Feature requests with a Baidu page showing the field ship fastest.

Not affiliated with Baidu, Inc. "Baidu Maps" and 百度地图 belong to their owners.

***

# Changelog

This Actor's version history is a separate document: https://apify.com/logiover/baidu-maps-scraper/changelog.md

# Actor input Schema

## `keywords` (type: `array`):

What to look for, as you would type it into Baidu Maps. Chinese keywords match best: 咖啡 (coffee), 餐厅 or 美食 (restaurants, food), 酒店 (hotels), 银行 (banks), 医院 (hospitals), 超市 (supermarkets), 加油站 (gas stations), 健身 (gyms), 药店 (pharmacies), or a brand such as 星巴克 (Starbucks) or 瑞幸咖啡 (Luckin). English brand names work too. Each keyword is searched in every city / area.

## `cities` (type: `array`):

Where to search. A city in Chinese, English or pinyin (北京 / Beijing / beijing, 上海, Shenzhen, Xi'an, Hong Kong), a Baidu city code (131 = Beijing) or a 6-digit admin code (110000), a district or county in Chinese (海淀区, 北京市朝阳区, 浦东新区, 昆山市), or a province (广东省 / Guangdong = every city in it). Shared English names pick the bigger city and say so in the log: write "Suzhou, Anhui" or 宿州 for the other one.

## `maxItems` (type: `integer`):

Stop after this many unique places across all searches. 0 = no limit (every matching place in your areas — a big city can hold tens of thousands for broad keywords like 美食). Big runs need a big enough "Maximum cost per run".

## `coverage` (type: `string`):

"Whole area" reads Baidu's own top results first and then splits the city (or district, circle, map view) into map circles until every circle is complete — thousands of places. "Top results only" returns just Baidu's own ranking for each keyword and city (what the app lists, ~100-200 places), which is the fastest.

## `includeDetails` (type: `boolean`):

Opens every place's Baidu page and adds description, aliases, postcode, the date Baidu created the place, detail tags, hotel category / facilities / services, nearby landmarks, booking links, sub-ratings, favourites and navigation counts. One extra request per place (about half the speed).

## `lat` (type: `string`):

Optional: search a circle around a point instead of (or in addition to) cities, e.g. 39.9087 for Tiananmen. Use with longitude, radius and the coordinate system of your point.

## `lng` (type: `string`):

Longitude of the circle's centre, e.g. 116.3975.

## `radiusMeters` (type: `integer`):

Radius of the nearby circle, 50 m to 200 km. Every matching place inside the circle is returned (the circle is split as needed).

## `coordinateSystem` (type: `string`):

WGS-84 is GPS / Google Maps outside China / OpenStreetMap. GCJ-02 is what Amap (Gaode), Tencent Maps and Apple Maps show in China. BD-09 is Baidu's own (what you copy from Baidu Maps).

## `uids` (type: `array`):

Optional: look up places you already know by their Baidu uid (24 hexadecimal characters, e.g. 261d9a8f181b11948c1a894d — the uid= value in a Baidu Maps place link). Useful to refresh a list.

## `startUrls` (type: `array`):

Optional: paste Baidu Maps links. Place links (…?uid=…, poiShareUid=…) are looked up; search links (map.baidu.com/search/咖啡/@x,y,13z?…\&wd=咖啡\&c=131) are searched over the visible map area (or the whole city when the link has only a city); mobile links (map.baidu.com/mobile/webapp/…) and j.map.baidu.com short links work too.

## `maxItemsPerSearch` (type: `integer`):

Optional cap per keyword × area (useful when one city would otherwise take the whole "Max places"). 0 = no per-search limit.

## `categoryFilter` (type: `array`):

Optional: keep only places whose Baidu category, tags or name contain one of these words, e.g. 咖啡厅 (drops bakeries and restaurants that Baidu mixes into a 咖啡 search) or 火锅.

## `minRating` (type: `string`):

Only places with at least this Baidu rating (places without a rating are left out when this is set).

## `onlyWithPhone` (type: `boolean`):

Leave out places without a phone number.

## `skipClosed` (type: `boolean`):

Baidu marks some places as temporarily closed (暂停营业); they are kept by default with status "temporarily closed".

## `proxyConfiguration` (type: `object`):

Used only as a fallback. The scraper reads Baidu Maps over a direct connection and Apify datacenter proxies side by side (no proxy cost to you); if Baidu refuses both, the proxy chosen here takes over.

## Actor input object example

```json
{
  "keywords": [
    "咖啡"
  ],
  "cities": [
    "北京"
  ],
  "maxItems": 20,
  "coverage": "full",
  "includeDetails": false,
  "radiusMeters": 1000,
  "coordinateSystem": "wgs84",
  "uids": [],
  "startUrls": [],
  "maxItemsPerSearch": 0,
  "categoryFilter": [],
  "minRating": "",
  "onlyWithPhone": false,
  "skipClosed": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All places collected in this run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "咖啡"
    ],
    "cities": [
        "北京"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/baidu-maps-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": ["咖啡"],
    "cities": ["北京"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/baidu-maps-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "咖啡"
  ],
  "cities": [
    "北京"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call logiover/baidu-maps-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,logiover/baidu-maps-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/GsyaZRnhXnFIyhKoy/builds/wCB9OYSG8xd42Fd7X/openapi.json
