解析影片 action=parse
GET https://www.doubanke.com/api?action=parse&key=YOUR_KEY&q=肖申克的救赎&format=json
根据豆瓣 ID、链接或片名解析。若片名匹配多部作品,返回 type: candidates 候选列表,需用 id + type 再次请求确认。
DEVELOPER API
通过 HTTP JSON 接口解析豆瓣电影/剧集,获取排版文本或结构化数据。本文档涵盖接入流程、鉴权、频控、状态码与完整字段说明。
本 API 提供两类能力:
所有接口均返回 application/json; charset=utf-8。成功时顶层包含 ok: true;失败时 ok: false 并附带 error 与 HTTP 状态码。
| 项目 | 说明 |
|---|---|
| 协议 | HTTPS 推荐(生产环境) |
| 方法 | GET / POST |
| 编码 | UTF-8 |
| 强制 Key | 未开启(建议仍使用 Key 以便统计与更高配额) |
注册并登录用户中心后,可获取以 dk_ 开头的 API Key。支持以下三种传递方式(任选其一):
| 方式 | 示例 |
|---|---|
Query 参数 key | ?key=dk_xxxxxxxx |
Query 参数 api_key | ?api_key=dk_xxxxxxxx |
请求头 X-API-Key | X-API-Key: dk_xxxxxxxx |
请求头 Authorization | Authorization: Bearer dk_xxxxxxxx |
Key 可在用户中心随时启用 / 停用 / 更换。停用或账号被禁用后,接口返回 403。
GET https://www.doubanke.com/api?action=parse&key=YOUR_KEY&q=肖申克的救赎&format=json
根据豆瓣 ID、链接或片名解析。若片名匹配多部作品,返回 type: candidates 候选列表,需用 id + type 再次请求确认。
GET https://www.doubanke.com/api?action=movie&key=YOUR_KEY&id=1292052&format=json
仅读取本站数据库中已存在的影片记录。若从未解析过该 ID,返回 500 及错误信息「缓存中没有这部影片」。
| 参数 | 位置 | 必填 | 说明 |
|---|---|---|---|
action | Query / Body | 否 | parse(默认)或 movie |
key / api_key | Query / Header | 建议 | API Key |
q / query | Query / Body | parse 时 | 豆瓣 ID、链接或片名 |
id | Query / Body | movie 时 / 候选确认时 | 豆瓣条目 ID |
type | Query / Body | 否 | 候选确认时传 movie 或 tv |
format | Query / Body | 否 | text(默认)、json 或 markdown(md 同义) |
refresh | Body / Query | 否 | 1 / true 强制刷新豆瓣数据与海报缓存 |
POST 请求可使用 Content-Type: application/json,字段名与 Query 相同,例如:
{
"query": "1292052",
"format": "json",
"refresh": false
}
type: result{
"ok": true,
"type": "result",
"douban_id": "1292052",
"title": "肖申克的救赎",
"original_title": "The Shawshank Redemption",
"year": "1994",
"rating": 9.7,
"rating_count": 3245678,
"poster": "https://你的域名/posters/1292052.jpg",
"poster_local": "https://你的域名/posters/1292052.jpg",
"poster_url": "https://img*.doubanio.com/...",
"formatted": "◎译 名 ...\n◎片 名 ...",
"cached": true,
"data": { "...": "结构化影片对象,见字段说明" }
}
当 format=json 时,poster、poster_local 及 data.poster 均返回本站海报的完整 URL(已保存到 posters/ 目录)。豆瓣原图仅保留在 poster_url 字段。若本地尚未保存海报,图片字段为空字符串。
当 format=markdown 时,额外返回 markdown 字段(与 formatted 相同),为可直接粘贴到 GitHub、Notion、Obsidian 等平台的 Markdown 卡片,含海报、表格与简介引用块。
type: candidates{
"ok": true,
"type": "candidates",
"query": "无间道",
"candidates": [
{
"id": "1307919",
"title": "无间道",
"year": "2002",
"sub_title": "Infernal Affairs",
"type": "movie",
"img": "https://你的域名/posters/1307919.jpg",
"url": "https://movie.douban.com/subject/1307919/"
}
]
}
确认候选后再次请求:action=parse&id=1307919&type=movie&q=无间道
{
"ok": false,
"error": "错误描述",
"code": "error_code"
}
| 状态码 | 含义 | 常见 code |
|---|---|---|
200 | 请求成功(含业务成功与候选列表) | — |
400 | 请求参数错误 | missing_query、missing_id、unknown_action |
401 | 未提供 API Key(管理员开启强制 Key 时) | missing_api_key |
403 | Key 无效、已停用或账号禁用 | invalid_api_key、api_key_disabled |
429 | 超过频控限制 | rate_limit_minute、rate_limit_daily、rate_limit_exceeded |
500 | 服务端或上游豆瓣错误 | server_error |
携带 API Key 的调用按用户等级限流;未带 Key 的匿名调用按 IP 限制。响应头会附带配额信息,便于客户端自行退避。
| 等级 | 分钟频率 | 每日上限 | 适合场景 |
|---|---|---|---|
| 免费用户 | 10 次 / 分 | 200 次 / 天 | 个人学习、接口联调、小规模脚本测试、偶尔查询影片信息。 |
| 初级用户 | 60 次 / 分 | 5,000 次 / 天 | 个人博客、小型网站、公众号工具、日调用量较低的应用集成。 |
| 中级用户 | 200 次 / 分 | 20,000 次 / 天 | 中小型平台、影视社区、内容站批量入库、多端应用与中频业务调用。 |
| 高级用户 | 不限 | 极高(按量抵扣) | 大型企业、高并发业务、数据平台与定制化对接;配额极高,按量抵扣,详谈专属方案。 |
新注册用户默认为免费用户。升级等级请联系管理员或在用户中心查看说明。
| 场景 | 限制 | 窗口 |
|---|---|---|
| 按 IP | 10 次 | 60 秒 |
| Header | 说明 |
|---|---|
X-RateLimit-Tier | 当前用户等级(free / basic / intermediate / advanced) |
X-RateLimit-Limit | 每分钟允许的最大请求数 |
X-RateLimit-Remaining | 当前分钟内剩余可用次数 |
X-RateLimit-Limit-Day | 每日允许的最大请求数 |
X-RateLimit-Remaining-Day | 今日剩余可用次数 |
X-RateLimit-Window | 分钟窗口长度(固定 60 秒) |
X-RateLimit-Reset | Unix 时间戳,建议在此时间后重试 |
Retry-After | 触发 429 时返回,建议等待秒数 |
触发限流时响应示例:
{
"ok": false,
"error": "本分钟调用次数已达上限(10 次 / 分)",
"code": "rate_limit_minute",
"retry_after": 60
}
建议:优先使用 API Key 获取对应等级配额;对 429 实施指数退避;避免高频 refresh=1 强制刷新。
将 YOUR_KEY 替换为用户中心获取的 Key,将域名替换为实际站点。
# 解析片名
curl -G "https://www.doubanke.com/api" \
--data-urlencode "action=parse" \
--data-urlencode "key=YOUR_KEY" \
--data-urlencode "q=肖申克的救赎" \
--data-urlencode "format=json"
# POST JSON
curl -X POST "https://www.doubanke.com/api?action=parse" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_KEY" \
-d '{"query":"1292052","format":"json"}'
const res = await fetch("https://www.doubanke.com/api?action=parse", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "YOUR_KEY"
},
body: JSON.stringify({ query: "1292052", format: "json" })
});
const data = await res.json();
if (!data.ok) throw new Error(data.error);
console.log(data.title, data.data);
import requests
resp = requests.get("https://www.doubanke.com/api", params={
"action": "parse",
"key": "YOUR_KEY",
"q": "1292052",
"format": "json",
}, timeout=30)
resp.raise_for_status()
data = resp.json()
if not data.get("ok"):
raise RuntimeError(data.get("error"))
print(data["title"])
$ch = curl_init("https://www.doubanke.com/api?action=parse");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: YOUR_KEY",
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
"query" => "1292052",
"format" => "json",
], JSON_UNESCAPED_UNICODE),
]);
$body = curl_exec($ch);
$data = json_decode($body, true);
if (!$data["ok"]) {
throw new RuntimeException($data["error"]);
}
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
u, _ := url.Parse("https://www.doubanke.com/api")
q := u.Query()
q.Set("action", "parse")
q.Set("key", "YOUR_KEY")
q.Set("q", "1292052")
q.Set("format", "json")
u.RawQuery = q.Encode()
resp, err := http.Get(u.String())
if err != nil { panic(err) }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
HttpClient client = HttpClient.newHttpClient();
String url = "https://www.doubanke.com/api?action=parse&key=YOUR_KEY&q=1292052&format=json";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
type: result)| 字段 | 类型 | 说明 |
|---|---|---|
ok | boolean | 是否成功 |
type | string | result / candidates |
douban_id | string | 豆瓣条目 ID |
title | string | 中文片名 |
original_title | string | 原名 |
year | string | 上映年份 |
rating | number|null | 豆瓣评分(0–10) |
rating_count | integer | 评分人数 |
poster | string | 本站海报完整 URL(format=json 时) |
poster_url | string | 豆瓣原始海报 URL(仅供参考) |
poster_local | string | 与 poster 相同,本站海报完整 URL |
is_tv | boolean | 是否为剧集 |
url | string | 豆瓣条目页链接 |
formatted | string | ◎ 风格排版文本;format=markdown 时为 Markdown 卡片 |
markdown | string | Markdown 卡片(仅 format=markdown 时返回) |
cached | boolean | 是否来自本站缓存(未实时抓取豆瓣) |
updated_at | string|null | 缓存更新时间 Y-m-d H:i:s |
data / movie | object | 结构化影片对象(内容相同) |
data 对象字段| 字段 | 类型 | 说明 |
|---|---|---|
douban_id | string | 豆瓣 ID |
title | string | 片名 |
original_title | string | 原名 |
aka | string[] | 又名列表 |
year | string | 年份 |
countries | string[] | 制片国家/地区 |
genres | string[] | 类型,如剧情、犯罪 |
languages | string[] | 语言 |
pubdates | string[] | 上映日期 |
durations | string[] | 片长或单集时长 |
episodes_count | integer | 集数(剧集) |
episodes_info | string | 集数说明 |
directors | object[] | 导演,含 name、latin_name |
writers | object[] | 编剧 |
actors | object[] | 主演(通常最多 8 人) |
rating | number|null | 评分 |
rating_count | integer | 评分人数 |
intro | string | 剧情简介 |
poster | string | 本站海报完整 URL |
poster_local | string | 本站海报完整 URL |
poster_url | string | 豆瓣原始海报 URL |
url | string | 豆瓣链接 |
imdb | string | IMDb ID,如 tt0111161 |
tags | string[] | 豆瓣标签 |
honors | string[] | 获奖信息 |
is_tv | boolean | 是否剧集 |
subtype | string | movie / tv |
card_subtitle | string | 卡片副标题 |
candidates[]| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 豆瓣 ID |
title | string | 标题 |
year | string | 年份 |
sub_title | string | 副标题/英文名 |
type | string | movie 或 tv |
img | string | 封面图;format=json 且本地已缓存时为本站完整 URL,否则为豆瓣地址 |
url | string | 豆瓣链接 |
本站对海报资源与 API 调用做了基础防护,可在后台 API 设置 → 安全与防盗 中调整。
JSON 返回的 poster 字段指向本站资源网关(/serve_asset 或经伪静态映射的 /posters/文件名)。开启防盗链后:
asset_token,URL 会附带 exp + sig 签名,在有效期内可跨站引用;token=你的密钥(与后台 asset_token 一致)供服务端拉取。Nginx 环境请在伪静态中加入 posters 重写规则,参见项目 rewrite/baota_nginx.conf。
未携带 API Key 的浏览器请求会校验 Origin / Referer 是否属于允许站点,防止第三方网页滥用本站接口。携带有效 Key 的调用不受此限制。
全站默认输出 X-Content-Type-Options、X-Frame-Options、Content-Security-Policy 等头;HTTPS 下启用 HSTS。
ok 字段。type: candidates 做二次选择,不要直接当作最终结果。429 时读取 retry_after 或 Retry-After 头后重试。format=text、json 和 markdown 有何不同?text 返回 ◎ 风格排版文本;json 侧重结构化 data;markdown 返回含海报、表格、简介引用块的 Markdown 卡片,适合论坛/GitHub/笔记软件。format=json 时,poster / poster_local 返回本站完整地址(经资源网关,可能含签名参数)。可直接用于本站或已授权域名下的展示;外站引用需配置允许来源或签名密钥。