【免费下载链接】browser-harness
Browser Harness | Self-healing harness that enables LLMs to complete any task.
世界银行开放数据(World Bank Open Data)通过 https://api.worldbank.org/v2 提供全球发展指标的免费 REST API,无需 API Key、无需登录、无需浏览器即可获取 GDP、人口、失业率等 29000+ 个指标。本文基于 browser-harness 仓库中的领域技能文档 world-bank/scraping.md,结合 helpers.py 中 http_get 的源码实现,完整讲解该 API 的响应结构、常用抓取工作流、URL 参数体系与全部踩坑点,读完即可在 browser-harness 环境中直接复制运行。
在 browser-harness 中调用 http_get
World Bank API 是纯 HTTP 接口,不需要启动浏览器。browser-harness 的领域技能文档(Domain Skills)遵循"能用普通 HTTP 请求解决就不用浏览器"的原则——src/browser_harness/SKILL.md 明确指出:公开页面、API、文档这类一次 http_get 就能读到的内容,应直接使用 HTTP 抓取,浏览器留给需要点击、输入、登录态、JS 渲染或反爬对抗的场景。
在 browser-harness 中,脚本通过 heredoc 方式交给 CLI 执行,helpers.py 中的核心原语会被自动导入进这些脚本(见 AGENTS.md 与 src/browser_harness/SKILL.md):
browser-harness <<'PY'
from helpers import http_get
import json
raw = http_get("https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD?format=json")
print(raw[:200])
PY
http_get 定义在 src/browser_harness/helpers.py,签名与行为如下:
def http_get(url, headers=None, timeout=20.0):
"""Pure HTTP — no browser. Use for static pages / APIs. Wrap in ThreadPoolExecutor for bulk.
When BROWSER_USE_API_KEY is set, routes through the fetch-use proxy (handles bot
detection, residential proxies, retries). Falls back to local urllib otherwise."""
源码级要点:
- 纯 HTTP 实现,不经过浏览器与 CDP,适用于静态页面与 API;
- 默认
timeout=20.0秒,可通过timeout参数调整; - 默认携带
User-Agent: Mozilla/5.0与Accept-Encoding: gzip,并自动解压 gzip 响应,返回解码后的文本; - 可传入
headers字典覆盖或追加请求头(如自定义 User-Agent); - 当环境变量
BROWSER_USE_API_KEY存在时,会尝试路由到fetch_use代理(处理反爬、住宅代理与重试),否则回退到本地urllib; - 适合大批量抓取时配合
ThreadPoolExecutor并发调用(文档中原生给出了并行抓取示例)。
第一步必读:响应永远是一个 2 元素 JSON 数组
World Bank API 的每个响应都是一个 2 元素 JSON 数组 [metadata, data]。索引 0 是分页元数据,索引 1 是数据数组。这是最大的坑——json.loads(raw) 得到的是 list 而不是 dict:
from helpers import http_get
import json
raw = http_get("https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD?format=json")
d = json.loads(raw)
meta = d[0] # {"page": 1, "pages": 2, "per_page": 50, "total": 66, ...}
rows = d[1] # list of data records
同时,务必在 URL 末尾追加 ?format=json——API 默认返回 XML,不带该参数时 json.loads 会直接失败。
常用工作流
以下工作流的输出均为文档作者于 2026-04-18 实测确认,可直接复制运行。
单国家、单指标
from helpers import http_get
import json
raw = http_get("https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD?format=json")
d = json.loads(raw)
meta, rows = d[0], d[1]
for r in rows:
if r["value"] is not None: # recent years often have null values
print(r["date"], r["value"])
# Confirmed output (2026-04-18):
# 2024 28750956130731.2
# 2023 27292170793214.4
# 2022 25604848907611.0
# ...
注意循环中的 if r["value"] is not None 过滤:近年数据(如 2025)以及数据稀疏的国家经常返回 null 值。
最近 N 个值(mrv 参数)
mrv(most recent values)会跳过空值年份,返回最近 N 个非临时(non-provisional)数据点:
from helpers import http_get
import json
raw = http_get(
"https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD"
"?format=json&mrv=5"
)
d = json.loads(raw)
for r in d[1]:
print(r["date"], r["value"])
# Confirmed output (2026-04-18):
# 2024 28750956130731.2
# 2023 27292170793214.4
# 2022 25604848907611.0
# 2021 23315080560000.0
# 2020 21060473613000.0
多国家、日期区间
国家代码在 URL 路径中用分号分隔,日期区间用 date=YYYY:YYYY:
from helpers import http_get
import json
raw = http_get(
"https://api.worldbank.org/v2/country/US;CN;GB/indicator/SP.POP.TOTL"
"?format=json&date=2000:2023&per_page=100"
)
d = json.loads(raw)
meta, rows = d[0], d[1]
print(f"Total records: {meta['total']}, pages: {meta['pages']}")
for r in rows:
print(r["country"]["value"], r["date"], r["value"])
# Confirmed: returns 8 records per page (50 default), date range honored exactly
# Countries: ['China', 'United States', 'United Kingdom']
# Dates: ['2000', '2001', ..., '2023']
所有国家、仅取最新值
mrv=1 配合 per_page=1000(API 单页上限),一次调用即可拿回全部 266 个实体的最新值:
from helpers import http_get
import json
raw = http_get(
"https://api.worldbank.org/v2/country/all/indicator/NY.GDP.PCAP.CD"
"?format=json&mrv=1&per_page=1000"
)
d = json.loads(raw)
meta, rows = d[0], d[1]
print(f"Countries returned: {len(rows)}") # 266 (includes aggregates)
# Filter out regional aggregates — they have no iso2Code or have aggregate ids
countries_only = [r for r in rows if len(r["country"]["id"]) == 2]
for r in sorted(countries_only, key=lambda x: -(x["value"] or 0))[:5]:
print(r["country"]["value"], r["date"], f"${r['value']:,.0f}")
# Confirmed output (2026-04-18):
# Luxembourg 2024 $135,605
# Norway 2024 $105,056
# ...
完整分页(抓取所有页)
通过 meta["pages"] 驱动循环,逐页追加:
from helpers import http_get
import json
def fetch_all_pages(base_url):
"""Fetch all pages of a World Bank API endpoint."""
all_rows = []
page = 1
while True:
url = f"{base_url}&page={page}" if "?" in base_url else f"{base_url}?page={page}"
d = json.loads(http_get(url))
meta, rows = d[0], d[1]
all_rows.extend(rows)
if page >= meta["pages"]:
break
page += 1
return all_rows
# Example: all US GDP data (66 years, 2 pages)
rows = fetch_all_pages(
"https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD"
"?format=json&per_page=50"
)
print(f"Total rows: {len(rows)}") # 66
non_null = [(r["date"], r["value"]) for r in rows if r["value"] is not None]
print(f"Non-null: {len(non_null)}, range: {non_null[-1][0]}–{non_null[0][0]}")
指标列表(发现可用指标)
from helpers import http_get
import json
raw = http_get("https://api.worldbank.org/v2/indicator?format=json&per_page=50")
d = json.loads(raw)
meta = d[0]
print(f"Total indicators: {meta['total']}, pages: {meta['pages']}")
# Confirmed: 29,511 indicators across 591 pages
for ind in d[1][:3]:
print(ind["id"], "-", ind["name"])
# 1.0.HCount.1.90usd - Poverty Headcount ($1.90 a day)
# ...
按主题获取指标
from helpers import http_get
import json
# Topic 3 = Economy & Growth
raw = http_get("https://api.worldbank.org/v2/topic/3/indicator?format=json&per_page=50")
d = json.loads(raw)
print(f"Economy & Growth indicators: {d[0]['total']}") # 306
for ind in d[1][:5]:
print(ind["id"], "-", ind["name"])
国家元数据
from helpers import http_get
import json
raw = http_get("https://api.worldbank.org/v2/country/US?format=json")
d = json.loads(raw)
c = d[1][0]
print(c["name"], c["capitalCity"], c["region"]["value"], c["incomeLevel"]["value"])
# United States Washington D.C. North America High income
# Filter countries by income level
raw = http_get("https://api.worldbank.org/v2/country?format=json&incomeLevel=LIC&per_page=300")
d = json.loads(raw)
print(f"Low-income countries: {d[0]['total']}") # 25
主题列表
from helpers import http_get
import json
raw = http_get("https://api.worldbank.org/v2/topics?format=json")
d = json.loads(raw)
for t in d[1]:
print(t["id"], t["value"])
# 1 Agriculture & Rural Development
# 2 Aid Effectiveness
# 3 Economy & Growth
# ... (21 topics total)
多指标并行抓取(ThreadPoolExecutor)
http_get 本身是阻塞式纯网络调用,适合放进线程池做批量并发。这是 helpers.py docstring 中明确推荐的批量用法:
from helpers import http_get
from concurrent.futures import ThreadPoolExecutor
import json
INDICATORS = {
"NY.GDP.MKTP.CD": "GDP (current US$)",
"SP.POP.TOTL": "Population",
"NY.GDP.PCAP.CD": "GDP per capita",
}
def fetch_indicator(ind_id):
url = (
f"https://api.worldbank.org/v2/country/US/indicator/{ind_id}"
f"?format=json&mrv=5"
)
d = json.loads(http_get(url))
return ind_id, d[1]
with ThreadPoolExecutor(max_workers=3) as ex:
results = dict(ex.map(lambda i: fetch_indicator(i), INDICATORS))
for ind_id, rows in results.items():
latest = next((r for r in rows if r["value"] is not None), None)
if latest:
print(f"{INDICATORS[ind_id]}: {latest['date']} = {latest['value']:,.2f}")
URL 参考
基础 URL
https://api.worldbank.org/v2
HTTP 会 302 重定向到 HTTPS。请始终直接使用 HTTPS,避免一次多余往返。
端点模式
| 端点 | 说明 |
|---|---|
/country/{code}/indicator/{id} | 单国家 + 单指标时间序列 |
/country/{c1};{c2};{c3}/indicator/{id} | 多国家(分号分隔) |
/country/all/indicator/{id} | 所有国家 |
/country/{code} | 国家元数据 |
/country | 所有国家元数据(可过滤) |
/indicator | 全部指标列表 |
/indicator/{id} | 单指标元数据 |
/topic/{id}/indicator | 某主题下的指标 |
/topics | 全部主题 |
查询参数
| 参数 | 取值 | 说明 |
|---|---|---|
format | json、xml(默认) | 始终设置 format=json |
per_page | 整数,默认 50,最大 1000 | 批量抓取设大更快 |
page | 整数,默认 1 | 分页 |
date | 2020、2000:2023 | 单年或冒号分隔区间 |
mrv | 整数 | 最近 N 个非空值 |
gapfill | Y | 与 mrv 配合时向前填充空值 |
incomeLevel | LIC、MIC、HIC、LMC、UMC | 按收入水平过滤国家 |
region | EAS、ECS、LAC、MEA、NAC、SAS、SSF | 按区域过滤国家 |
常用指标 ID(2026-04-18 实测可用)
| ID | 名称 |
|---|---|
NY.GDP.MKTP.CD | GDP (current US$) |
NY.GDP.PCAP.CD | GDP per capita (current US$) |
SP.POP.TOTL | Population, total |
SL.UEM.TOTL.ZS | Unemployment (% of labor force) |
FP.CPI.TOTL.ZG | Inflation, consumer prices (%) |
NE.EXP.GNFS.ZS | Exports of goods and services (% of GDP) |
SP.DYN.LE00.IN | Life expectancy at birth |
SE.ADT.LITR.ZS | Literacy rate, adult total (%) |
EG.USE.PCAP.KG.OE | Energy use per capita (kg of oil equiv.) |
查找更多指标:https://api.worldbank.org/v2/indicator?format=json&per_page=50&page=N
国家代码(ISO2)
使用标准 ISO 3166-1 alpha-2 代码:US、CN、GB、DE、JP、IN、BR 等。特殊值 all 表示所有国家。
响应结构
每个端点都返回 2 元素数组,元数据元素包含分页信息,第二元素为数据记录列表:
[
{
"page": 1,
"pages": 2,
"per_page": 50,
"total": 66,
"sourceid": "2",
"lastupdated": "2026-04-08"
},
[
{
"indicator": {"id": "NY.GDP.MKTP.CD", "value": "GDP (current US$)"},
"country": {"id": "US", "value": "United States"},
"countryiso3code": "USA",
"date": "2024",
"value": 28750956130731.2,
"unit": "",
"obs_status": "",
"decimal": 0
},
...
]
]
国家元数据端点返回同样的 2 元素结构,但索引 1 中是 country 对象而非指标行。
Gotchas:全部踩坑点汇总
以下条目全部来自领域技能文档中的实测经验,是抓取 World Bank API 最容易出错的地方:
-
响应永远是 2 元素数组,不是 dict。
d = json.loads(raw)得到的是 list。d[0]是分页元数据,d[1]是数据列表。直接访问d["page"]会抛TypeError。这是最常见的错误。 -
value可能为 null。 近年份(如 2025)和数据稀疏国家经常返回null。使用前务必检查if r["value"] is not None;或用mrv=N让 API 自动跳过空值。 -
务必追加
?format=json。 默认响应格式是 XML。不带该参数会得到无法被json.loads解析的 XML 字符串。 -
all/indicator/{id}包含区域聚合。 "所有国家"端点返回 266 个实体,包含 "Africa Eastern and Southern"(id: "ZH")这类区域聚合。用len(r["country"]["id"]) == 2过滤出真实国家(ISO2 代码恒为 2 字符)。 -
多国家用 URL 路径中的分号,不是查询字符串。 正确写法是
country/US;CN;GB/indicator/...,?countries=US,CN,GB或逗号分隔都无效。 -
HTTP 302 将 HTTP 重定向到 HTTPS。 直接使用
https://避免额外一次往返。 -
元数据中的
per_page有时是字符串、有时是整数。 某些端点返回"per_page": "50"(字符串),另一些返回"per_page": 50(整数)。不要直接==比较,先转换:int(meta["per_page"])。 -
无效国家代码返回错误对象而非 2 元素数组。 错误响应形如
[{"message": [{"id": "120", "key": "Invalid value", ...}]}]——只有 1 个元素的错误 dict。访问d[1]前先检查isinstance(d[0], dict) and "message" in d[0]。 -
mrv+gapfill=Y会把最新值向前填充到未来年份。 若 2024 是最新数据点且设了mrv=3,gapfill=Y会返回 2025(当前年份)并复制 2024 的值。适合"当前值"查询,但填充出来的日期具有误导性。 -
API 未文档化速率限制,但稳定 3 req/s 是安全的。 接口可承受突发请求(文档实测
ThreadPoolExecutor(max_workers=3)并行无压力)。若要爬取数千个指标,建议页间加time.sleep(0.5)。 -
date区间返回的记录按最新在前排序。 区间内结果按年份降序。需要升序时抓取后自行排序:sorted(rows, key=lambda r: r["date"])。 -
指标 ID 区分大小写。
ny.gdp.mktp.cd会返回错误;必须使用大写点分形式NY.GDP.MKTP.CD。
小结
World Bank Open Data API 是 browser-harness 中"纯 HTTP 即可完成"类任务的典型代表:无需浏览器、无需认证,仅靠 http_get 与 json.loads 即可完成从单指标时间序列到全量 29511 个指标的各类抓取。核心纪律只有三条:响应是 2 元素数组(d[0] 元数据 / d[1] 数据)、始终带 ?format=json、对 null 值做好防御。在此基础上结合 mrv、per_page=1000 与 ThreadPoolExecutor,即可高效、稳健地构建全球经济数据管道。相关领域技能文件见 world-bank/scraping.md,http_get 底层实现见 src/browser_harness/helpers.py。
【免费下载链接】browser-harness
Browser Harness | Self-healing harness that enables LLMs to complete any task.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



