ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用Python调用维基与TMDB API,从零搭建影视人物近况查询工具

2026/9/5 2:55:29 拓冰建站 浏览量
用Python调用维基与TMDB API,从零搭建影视人物近况查询工具 前些天在一个影迷群里看到有人问“老版《X战警》里演琴·格蕾的演员现在到底还有没有在拍戏怎么查她的最新动态才靠谱”大家回答五花八门有的是凭记忆说“早退休了”有的贴出好几年前的旧闻真正能拿出可靠依据的人很少。这个问题看起来是个娱乐话题但如果从技术角度去看它其实是一个很典型的数据获取与聚合需求把某个公众人物的最新公开动态整理成结构化信息。只要我们掌握了正确的数据源和接口调用方式不仅能查法米克·詹森还能查任何一位导演、演员或者编剧。所以这篇文章我不打算去讨论八卦。我会带大家从零搭建一个“影视人物近况查询工具”用 Python 调用维基百科和 TMDB 的公开接口以“法米克·詹森”为示例把她的基本资料、近年作品、页面更新情况抓下来并整理成表格。整个过程会覆盖环境准备、API 调试、数据清洗、异常处理和工程落地新手照做也能跑出结果。1. 什么是“人物近况查询”为什么需要一套工具1.1 先理解数据问题当我们想了解一位演员的“现状”时通常关心的信息包括她出生于哪一年国籍是什么近三年有没有新电影或剧集她的公开作品时间线是怎样的最近是否有比较明显的消息更新。这些信息分散在不同网站上维基百科有基础人物词条TMDB 有影视作品库新闻网站有动态报道。如果手动逐个网页去翻效率很低而且很容易被过时信息误导。如果我们把“现状”重新定义成可查询、可对比、有时间戳的结构化数据这个问题就变成了一个标准的后端数据采集任务。1.2 工具要解决的核心问题一个完整的“演员现状查询工具”应该做到输入演员姓名自动匹配到正确的、唯一的 ID拉取人物的基础档案字段拉取她的影视作品列表并按年份排序通过人物资料页的更新信息来观察近期是否有内容变动把结果输出成表格方便快速浏览。1.3 常见应用场景影迷自建小项目用来跟踪喜欢的演员影视行业从业者做选角调研内容运营人员制作“明星近况”类专题数据课程练习用来演示公开 API 的数据获取与清洗。理解了需求之后下面我们就开始设计技术方案。2. 环境准备与数据源说明2.1 技术选型本项目的核心目标是快速获取公开数据并进行简单整合因此不需要引入太重型的框架。推荐环境如下依赖版本说明用途Python3.8 及以上开发语言requests2.25 及以上发起 HTTP 请求jsonPython 内置解析接口数据timePython 内置控制请求频率pandas1.3 及以上可选将结果整理成表格如果你的机器上已经有 Python 环境只需要安装 requests 和 pandaspip install requests pandas需要注意不同版本的接口返回字段可能存在细微差异所以建议将依赖版本固定到 requirements.txt 中。下面是一个参考文件内容requests2.31.0 pandas2.0.32.2 数据源选型本案例中我们优先选择无需复杂授权的公开数据源降低入门门槛。数据源能提供什么是否有 API Key中文维基百科 API人物简介、词条内容、修订记录不需要TMDB API人物 ID、生日、出生地、影视作品列表需要注册后免费申请为什么选择这两个源维基百科适合获取“介绍性摘要”和“页面更新状态”TMDB 更适合获取结构化的“演员作品列表”两者可以互补维基百科偏文本内容TMDB 偏影视数据库。2.3 整体流程设计整体流程可以拆解成四个步骤通过维基百科搜索接口确认演员的准确词条名调用维基百科摘要接口获取人物简介调用 TMDB 搜索接口匹配演员在影视数据库中的唯一 ID调用 TMDB 人员作品接口按时间拉取作品列表并输出。为了遵守接口服务条款我们会在每次请求之间加入 1 秒左右的延时避免高频访问给对方服务器造成压力。3. 维基百科 API 的使用与解析3.1 为什么先调用搜索接口很多人会直接构造一个“固定词条链接”例如url https://zh.wikipedia.org/w/api.php?actionquerytitles法米克·詹森这种做法在词条名完全正确时可用但一旦遇到简体中文和繁体中文差异、别名、重定向等问题接口很可能返回“页面不存在”。更稳妥的方式是先调用搜索接口拿到准确词条标题再去请求摘要。示例搜索“法米克·詹森”。import requests def search_wiki_page(keyword: str) - list: 根据关键词在中文维基百科中搜索匹配的词条。 返回前 5 条搜索结果包含页面标题。 url https://zh.wikipedia.org/w/api.php params { action: query, list: search, srsearch: keyword, format: json, utf8: 1, srlimit: 5, } headers { User-Agent: ActorStatusBot/1.0 (个人学习项目演示) } resp requests.get(url, paramsparams, headersheaders) resp.raise_for_status() data resp.json() search_results data.get(query, {}).get(search, []) results [] for item in search_results: results.append( { title: item[title], pageid: item[pageid], snippet: item.get(snippet, ).replace(span class\searchmatch\, ).replace(/span, ), } ) return results if __name__ __main__: items search_wiki_page(法米克·詹森) for i, item in enumerate(items, 1): print(f{i}. {item[title]} (页面ID: {item[pageid]}))运行结果并不是固定的但正常情况下输出中应该会包含一个以“法米克·詹森”为标题的中文维基条目同时可能还有其他近义词条。搜索之后我们需要让用户从中选择一个词条标题再去获取摘要。3.2 获取人物摘要拿到精确的页面标题后就可以请求该页面的引言部分。维基百科提供了一种很方便的提取方式通过propextracts并指定exintro1可以只返回页面开头的一段不带 HTML 标签的纯文本。def get_page_extract(title: str) - str: 根据词条标题获取维基百科页面的引言摘要。 url https://zh.wikipedia.org/w/api.php params { action: query, prop: extracts, explaintext: 1, exintro: 1, titles: title, format: json, utf8: 1, } headers { User-Agent: ActorStatusBot/1.0 (个人学习项目演示) } resp requests.get(url, paramsparams, headersheaders) resp.raise_for_status() data resp.json() pages data.get(query, {}).get(pages, {}) for page_id, page in pages.items(): if page_id -1: return return page.get(extract, ) return if __name__ __main__: text get_page_extract(法米克·詹森) print(text[:300] if text else 没有抓到正文内容)这一段返回内容通常是这位演员最基础也最准确的公开介绍例如国籍、出生时间、代表角色等。文本可以直接保存到本地文件也可以进一步做关键词分析。3.3 获取页面最近修订时间“人物现状”里有一个容易被忽略的指标维基百科词条最近一次被编辑的时间。如果某个词条近期被大量修订很可能是因为人物有新的作品上映或者发生了被媒体广泛报道的事件。把修订时间作为一个“近期活跃度参考信号”是合理的。def get_page_revision_info(title: str) - dict: 获取词条最近一次修订的时间和编辑者名称。 url https://zh.wikipedia.org/w/api.php params { action: query, prop: revisions, titles: title, rvlimit: 1, rvprop: timestamp|user|comment, format: json, utf8: 1, } headers { User-Agent: ActorStatusBot/1.0 (个人学习项目演示) } resp requests.get(url, paramsparams, headersheaders) resp.raise_for_status() data resp.json() pages data.get(query, {}).get(pages, {}) for page_id, page in pages.items(): revisions page.get(revisions, []) if not revisions: return {} rev revisions[0] return { title: page.get(title, ), last_edit_time: rev.get(timestamp, ), last_editor: rev.get(user, ), edit_comment: rev.get(comment, ), } return {}这里的关键参数是rvprop它指定了需要返回的时间戳、用户和编辑摘要。如果某个演员近期有新作品维护者通常会更新其作品列表附带一句类似“更新2024年新剧”的编辑说明。4. TMDB 接口从“人名”到“影视作品列表”4.1 注册与获取 API KeyTMDB 是国际上使用非常广泛的电影数据库之一它的开放 API 对个人开发者很友好。使用前需要先去其官网注册账号然后在“设置 - API”页面申请一个 Key。申请成功后会得到一串类似下面格式的字符串1234567890abcdef1234567890abcdef需要注意这串 Key 相当于你的个人凭证不能上传到公开代码仓库。建议写入环境变量或者存放到独立的配置文件中。在代码中读取环境变量的示例import os TMDB_API_KEY os.environ.get(TMDB_API_KEY, ) if not TMDB_API_KEY: print(请先设置环境变量 TMDB_API_KEY) exit(1)4.2 人物搜索接口TMDB 的人物搜索接口路径为GET https://api.themoviedb.org/3/search/person核心参数如下参数说明api_key你的 API Keyquery搜索关键词language返回语言例如 zh-CNpage页码默认 1下面用“Famke Janssen”作为关键词进行搜索def search_person_tmdb(person_name: str, language: str zh-CN) - list: 在 TMDB 中搜索人物返回人物基础匹配列表。 url https://api.themoviedb.org/3/search/person params { api_key: TMDB_API_KEY, query: person_name, language: language, page: 1, } resp requests.get(url, paramsparams) resp.raise_for_status() data resp.json() results data.get(results, []) persons [] for r in results: persons.append( { id: r.get(id), name: r.get(name), original_name: r.get(original_name, ), known_for_department: r.get(known_for_department, ), popularity: r.get(popularity, 0), profile_path: r.get(profile_path), known_for_titles: [ item.get(title) or item.get(name) or for item in (r.get(known_for) or []) ][:3], } ) return persons搜索结果中会有一个id字段这是 TMDB 内部的人物唯一标识。例如老版 X 战警中扮演琴·格蕾的演员法米克·詹森在 TMDB 中会匹配到唯一一个 ID。后续查询作品时不需要再传递中文名或英文名只需要使用这个数字 ID这样最准确也避免了同名干扰。4.3 人物详情接口拿到person_id后可以继续请求人物详情GET https://api.themoviedb.org/3/person/{person_id}示例代码def get_person_detail(person_id: int, language: str zh-CN) - dict: 获取人物的生日、出生地、简介等基础资料。 url fhttps://api.themoviedb.org/3/person/{person_id} params { api_key: TMDB_API_KEY, language: language, } resp requests.get(url, paramsparams) resp.raise_for_status() data resp.json() return { id: data.get(id), name: data.get(name, ), birthday: data.get(birthday, ), deathday: data.get(deathday, ), birthplace: data.get(place_of_birth, ), biography: data.get(biography, ), popularity: data.get(popularity, 0), }4.4 影视作品列表接口查询某位演员的全部影视作品接口路径是GET https://api.themoviedb.org/3/person/{person_id}/movie_credits返回数据中有一个cast列表包含她出演过的电影。我们最关心的是电影名称扮演的角色名上映日期角色是否为“琴·格蕾”这种重要角色。def get_person_movie_credits(person_id: int, language: str zh-CN) - list: 获取人物参与演出的电影列表。 url fhttps://api.themoviedb.org/3/person/{person_id}/movie_credits params { api_key: TMDB_API_KEY, language: language, } resp requests.get(url, paramsparams) resp.raise_for_status() data resp.json() cast data.get(cast, []) movies [] for item in cast: release_date item.get(release_date, ) movies.append( { movie_id: item.get(id), title: item.get(title, ), character: item.get(character, ), release_date: release_date, year: release_date[:4] if release_date else , popularity: item.get(popularity, 0), } ) # 按年份排序 movies.sort(keylambda x: x[release_date], reverseTrue) return movies按年份降序排列之后我们可以一眼看出这位演员近几年有没有作品。这一步直接回答了“她是否还在持续接戏”这个信息需求。5. 把这些能力组装成一个 CLI 工具5.1 项目结构我建议把项目文件拆成下面这样便于后续维护actor_status/ ├── requirements.txt ├── config.py ├── wiki_api.py ├── tmdb_api.py ├── main.py └── output/config.py存放全局配置wiki_api.py封装维基百科接口tmdb_api.py封装 TMDB 接口main.py是入口脚本output目录存放运行结果。5.2 主入口代码下面是一个简化版主入口它输入人名后依次获取词条摘要、TMDB ID 以及近五年的作品。import json import time from datetime import datetime import pandas as pd import config from wiki_api import get_page_extract, search_wiki_page from tmdb_api import get_person_movie_credits, get_person_detail, search_person_tmdb def main(): keyword Famke Janssen print(f正在检索{keyword}) # 第 1 步在中文维基百科中搜索词条 wiki_items search_wiki_page(keyword) if wiki_items: title wiki_items[0][title] extract get_page_extract(title) print(维基词条, title) print(简介, extract[:200] if extract else 无) else: print(维基百科未找到该词条) time.sleep(1) # 第 2 步在 TMDB 中搜索人物 persons search_person_tmdb(keyword, languagezh-CN) if not persons: print(TMDB 未找到该演员) return person_id persons[0][id] # 第 3 步获取人物详情 detail get_person_detail(person_id) print(演员姓名, detail[name]) print(出生日期, detail[birthday]) print(出生地, detail[birthplace]) time.sleep(1) # 第 4 步获取影视作品并筛选近 5 年 credits get_person_movie_credits(person_id) df pd.DataFrame(credits) current_year datetime.now().year recent df[df[year].astype(str).str.isdigit()] recent recent[recent[year].astype(int) current_year - 5] recent recent.sort_values(release_date, ascendingFalse) print(\n近 5 年参与演出电影) if recent.empty: print(暂无数据需要扩大年份范围查看全部作品。) else: result recent[[release_date, title, character]] print(result.to_string(indexFalse)) # 保存到 JSON 文件 output { keyword: keyword, person_id: person_id, detail: detail, recent_credits: recent.to_dict(orientrecords), query_time: datetime.now().strftime(%Y-%m-%d %H:%M:%S), } with open(output/actor_result.json, w, encodingutf-8) as f: json.dump(output, f, ensure_asciiFalse, indent2) print(\n结果已保存至 output/actor_result.json) if __name__ __main__: main()这里需要注意第一轮搜索时没有指定语言为了让关键词匹配率更高我使用的是英文名“Famke Janssen”。在 TMDB 里演员名通常以英文原名为准中文名是翻译后的附加字段。5.3 运行与验证运行入口文件cd actor_status python main.py如果配置正确你会看到类似下面的流程输出正在检索Famke Janssen 维基词条法米克·詹森 简介法米克·詹森Famke Janssen是一位荷兰籍女演员... 演员姓名法米克·詹森 出生日期1964-11-05 出生地荷兰阿姆斯特尔芬 近 5 年参与演出电影 release_date title character ...需要说明的是演员的真实动态数据是持续变化的所以本文不列出具体的“现状结论”。当你的工具跑通后任何时刻执行一次得到的就是当时最新结果。6. 数据清洗与结果展示优化6.1 为什么需要清洗接口返回的数据往往存在以下问题release_date为空导致按年份过滤时无法判断同一个演员会出现重复条目有些电影并非真实上映而是处于“计划中”状态但 TMDB 也会返回角色字段可能为空。如果不做清洗直接展示会产生误导。建议在拿到原始数据后增加过滤条件def clean_credits(movies: list) - list: 清洗影视作品数据。 - 去掉 release_date 为空的记录 - 去掉重复 movie_id - 将 character 空值替换为“未知” cleaned [] seen_ids set() for m in movies: if not m.get(release_date): continue if m[movie_id] in seen_ids: continue seen_ids.add(m[movie_id]) if not m.get(character): m[character] 未知 cleaned.append(m) return cleaned6.2 用 DataFrame 做统计分析如果只是想看“最近十年参与多少部作品”“合作最多的是哪类题材”pandas 非常合适df pd.DataFrame(cleaned_movies) df[year] df[release_date].str[:4] df[year] pd.to_numeric(df[year], errorscoerce) # 按年份统计作品数 yearly_count df.groupby(year).size().reset_index(namecount) print(yearly_count[yearly_count[year] 2015])这样得到的是一个趋势表。把趋势数据再画成折线图就是一份完整的“演员活跃度可视化”结果。7. 常见问题与排查思路在这个项目实战中最容易出问题的环节往往是请求参数和返回结构。下面整理了一张高频问题表。问题现象常见原因解决思路维基百科返回badtitle词条名写错或使用了繁体先用搜索接口确认标题再传入 extractsTMDB 返回 401 错误API Key 无效或未设置环境变量检查环境变量确认 Key 没有暴露特殊字符TMDB 返回 429 错误请求频率超过限制加入time.sleep(1)或使用更长的间隔搜索结果为空中文名在 TMDB 中未匹配到先使用英文原名搜索再回填中文名人物 ID 对不上同名演员在不同地区有不同词条优先选择original_name匹配且known_for_department为 Acting 的记录作品列表年份缺失TMDB 部分条目尚未补全年份将缺失年份的条目单独存入待补全列表不要直接丢弃写入 JSON 时中文乱码没有指定ensure_asciiFalse在json.dump()中设置ensure_asciiFalse, encodingutf-8运行到一半被反爬缺少 User-Agent 或请求过于频繁为 requests 设置浏览器风格 User-Agent并使用限速策略7.1 维基搜索接口返回空结果怎么办先手动在浏览器中访问https://zh.wikipedia.org/w/api.php?actionquerylistsearchsrsearchFamke%20Janssenformatjson如果浏览器能返回数据Python 却取不到重点检查是不是请求头里的User-Agent太简单。维基百科对默认的python-requestsUser-Agent 有过限制建议改成headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ActorStatusDemo/1.0 }7.2 TMDB 请求成功但演员才 1 条结果排查思路检查query用的是不是原名检查语言参数是否为en-US因为部分演员在中文词库中资料较少如果使用中文名找不到改用英文名搜索后再做语言切换。7.3 如何避免数据源不稳定影响项目建议你做两级缓存第一级本地 JSON 缓存每次请求前先读取避免重复请求第二级在内存中使用字典记录已经访问过的 URL。下面是简化的缓存逻辑import os import json CACHE_DIR cache def get_cache(url: str) - dict: filename os.path.join(CACHE_DIR, str(abs(hash(url))) .json) if os.path.exists(filename): with open(filename, r, encodingutf-8) as f: return json.load(f) return None def set_cache(url: str, data: dict): os.makedirs(CACHE_DIR, exist_okTrue) filename os.path.join(CACHE_DIR, str(abs(hash(url))) .json) with open(filename, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2)注意hash()在不同 Python 进程中可能不一致实际项目中建议使用hashlib.md5来生成稳定的缓存文件名。8. 从“能跑”到“工程级”的最佳实践8.1 不要把 API Key 写进代码很多新手在第一次跑通接口后会直接把 Key 写进.py文件里提交到 GitHub。这是一个高危操作。正确做法是将 Key 放入系统的环境变量或者使用.env文件并让.gitignore忽略它。export TMDB_API_KEY你的key8.2 接口调用要“能省则省”公开 API 虽然免费但都有速率限制。建议这样做相同参数请求结果做 24 小时缓存只在每天固定时间增量更新批量查询时使用小请求间隔 1 到 2 秒。8.3 增加重试机制网络请求不可能永远一帆风顺。偶尔一次超时是正常现象建议对 5xx 错误做指数退避重试import time import requests def request_with_retry(url, params, headers, retries3): for i in range(retries): try: resp requests.get(url, paramsparams, headersheaders, timeout10) resp.raise_for_status() return resp.json() except requests.exceptions.RequestException as e: print(f第 {i1} 次请求失败{e}) time.sleep(2 ** i) raise RuntimeError(请求失败次数过多)8.4 对“现状”类数据的边界意识这里需要特别强调一个安全问题我们在做数据抓取时一定要区分“公开资料整理”和“个人隐私窥探”。可以抓取演员主动公开的职业信息、影视作品、百科简介不应该去抓取未经授权的私人住址、联系方式、家庭隐私、行踪轨迹也不应该把抓取到的个人信息用于骚扰、攻击或其他非法用途。本文演示的所有接口都是数据方明确提供给开发者使用的公开接口。抓取的对象也仅限于电影工作者的职业资料。如果你的业务需要爬取其他网站内容请先阅读对方网站的 robots.txt 和服务条款确保行为合法合规。8.5 数据结果要保留“采集时间”任何人物动态查询结果都有时效性。在存档时必须记录数据的采集时间。否则三天后你再看这份数据很可能已经无法判断它反映的是哪个时间点的状态。建议把采集时间写入字段{ query_time: 2025-06-20 14:30:00, person_id: 12345, source: TMDB }8.6 异常分支也要有日志当项目逐渐扩大命令行 print 已经不够用。建议引入标准库loggingimport logging logging.basicConfig( levellogging.INFO, format%(asctime)s - %(name)s - %(levelname)s - %(message)s, filenameactor_status.log, )这样即使脚本在半夜定时执行时发生异常你也可以在日志文件中看到完整的调用链和报错信息。9. 扩展方向与进阶优化如果你已经成功跑通了上面的代码下面这些方向可以进一步探索。9.1 查询多个人物并对比把代码中的keyword从单个字符串改成列表批量查询多位演员然后用 DataFrame 横向对比年龄、作品数量、近三年活跃度等指标。9.2 加入电视剧数据TMDB 不仅支持电影查询还支持电视剧查询。接口是GET https://api.themoviedb.org/3/person/{person_id}/tv_credits如果演员近几年主要作品集中在剧集领域只查电影会漏掉重要信息。9.3 做成简单的 Web 服务当查询逻辑稳定后可以做一个小型 Flask 或 FastAPI 应用对外提供类似下面的接口GET /actor/status?nameFamke%20Janssen内部逻辑复用本文的wiki_api.py和tmdb_api.py返回标准化 JSON。这样前端页面就可以输入任意演员姓名实时查看动态。9.4 定时任务更新如果你想把“演员近况”做成每日更新的小看板可以设置 crontab 任务0 9 * * * cd /home/user/actor_status /usr/bin/python3 main.py actor_daily.log 21每天早上 9 点自动运行一次并把结果保存到output目录长期积累后就能形成一个时间序列数据库用来做演员热度变化分析。9.5 可视化展示把每年上映作品数和词条修订时间连接起来可以画出一张“人物活跃时间线”。常用的方案是使用pandas做数据清洗使用pyecharts或plotly画时间趋势图使用streamlit搭建交互页面让用户自己搜索感兴趣的人物。10. 总结回到最开始的问题老版琴·格蕾扮演者法米克·詹森目前状态怎么样当你读完这篇教程你应该已经意识到与其听别人转述或者靠零散新闻猜答案不如直接写一段代码去公开数据源里查证。通过维基百科 API 获取词条基调和最近变更记录再通过 TMDB API 获取演员 ID 与作品序列只要跑通一次任何人都能用同样的方法查到自己关心的演员——不管 TA 是电影主角、老牌配角还是刚出道的新人。这套方法的关键除了代码本身更重要的是对数据源的契约理解、异常处理意识以及保存采集时间的好习惯。我希望你不仅能复制出上面的代码还能把它改造适配到自己的场景中。如果你亲手把它运行成功一定会在接口调用和数据处理上多一层真实体感。接下去试着换成你喜欢的另一位演员观察一下结果有什么不同。