ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

IMFDB-API实战指南:影视道具数据抓取与结构化解析

IMFDB-API实战指南:影视道具数据抓取与结构化解析 做影视行业的资料整理、游戏美术做道具考据、或者单纯是电影爱好者在做数据库类项目时都会遇到一个尴尬情况信息源太散了。IMDb只能查到演员和剧情想要确认某部电影里出现过的具体道具型号、对应角色、使用场景得靠人去一帧帧翻截图效率极低。这时候IMFDB-API就能帮上大忙。先说明白这个 API 是什么。IMFDBInternet Movie Firearm Database是一个专门收录影视作品中出现过的道具武器资料的数据库里的条目按电影、剧集、游戏划分每部作品一个页面列出相关道具型号、持用角色、场景描述和截图证据。这个站点跑在 MediaWiki 架构上所以社区里常说的“IMFDB-API”其实指的是对这套 MediaWiki API 接口的封装调用方式。通过它你可以程序化地搜索影视条目、抓取页面结构、批量提取道具清单把一个纯人工查阅的网站变成可编程的数据源。这篇指南会从接口原理、请求参数、代码实现到踩坑心得完整讲一遍怎么用好这个 API。内容主要面向这几类人想自动整理电影道具资料的研究型影迷、需要做数据抓取与结构化处理的开发新手、以及想给自己的影视资料站或游戏设定集做素材底座的创作者。1. IMFDB-API 的整体设计与调用思路1.1 数据源的本质一个开放的 MediaWiki 站点要理解 IMFDB-API得先理解 IMFDB 的内容组织形式。它和维基百科一样每一部电影或游戏对应一个词条页面比如你输入“John Wick”就能找到专门一页列出该系列电影中出现的各类道具型号、持用角色、使用场景、以及对应的截图链接。页面内部大量使用表格、列表和图片说明内容详细但格式高度依赖人类阅读。这个底层架构决定了 IMFDB-API 不是一套独立的“官方数据接口”而是复用 MediaWiki 自带的公开 API。好处是稳定、文档成熟、几乎所有 MediaWiki 站点通用坏处是它返回的原始数据大多是 wikitext维基文本和 JSON 混合体不能指望它给你一张干净的 SQL 表。想转成理想的结构化数据得自己做一层清洗和解析。1.2 核心接口能力全景MediaWiki API 提供的功能很多和 IMFDB 深度结合后最常用的几个能力是关键词搜索按电影名、道具型号、角色名搜索页面返回匹配条目列表。页面内容抓取直接拉取指定页面的 wikitext 源码或解析后的 HTML。分类枚举按 IMFDB 站点内的分类比如“电影”“电子游戏”“电视剧”批量列出全部条目。图片信息获取提取页面中的图片文件名和说明方便做视觉存档。重定向处理自动跟随词条重定向避免“原名跳转到规范名”造成的数据丢失。这些能力组合起来已经能覆盖一个初级影视资料检索工具 90% 的需求。1.3 为什么选这种方案而不是直接爬网页可能有朋友会问既然 IMFDB 就是普通网页我直接写个爬虫抓 HTML 不就行了理论上可以但不划算。直接爬网页要处理 HTML 标签、CSS 类名变化、页面布局调整网站只要改版一次爬虫代码就得跟着返工。而 MediaWiki API 是站点面向开发者提供的正式接口返回 JSON 结构字段相对固定修改成本低得多。更重要的是这样避免了频繁请求对站点造成压力也更符合一个工具类项目该有的优雅度。2. 开始前的必备知识接口地址与请求参数拆解2.1 找到正确的 API 入口IMFDB 的 API 入口就一个https://www.imfdb.org/api.php后面所有请求都用这个端点通过不同的 action 参数切换功能。最常用的是actionquery它可以同时承担搜索、信息获取、分类枚举等任务。在浏览器里直接访问也可以返回的是 JSON 文本在代码里就是一次普通的 HTTP GET 请求。2.2 参数选择背后的逻辑MediaWiki API 参数多但核心就这几个掌握了就够用搜索条目actionquery listsearch srsearchJohn Wick formatjsonlistsearch表示执行一次全文搜索srsearch是搜索关键词。返回结果会包含页面标题、页面ID、匹配片段等信息。适合先拿关键词定位到自己要的页面名。获取页面内容actionparse pageJohn_Wick propwikitext formatjsonactionparse可以把指定页面解析出来propwikitext是拿原始维基文本这个最适合做二次解析。如果想要 HTML 版本就把prop换成text。我自己做数据清洗时首选 wikitext因为它的结构化标记比如表格竖线语法比 HTML 的 class 属性更好提取。枚举分类成员actionquery generatorcategorymembers gcmtitleCategory:Movies gcmtypepage formatjson这条命令会返回属于Movies这个分类下的所有页面标题。gcmtitle要填站点实际的分类名建议先在网页端浏览确认分类的真实命名。批量抓取多个页面actionquery titlesJohn_Wick|John_Wick_2|John_Wick_3 proprevisions rvpropcontent formatjson这里用竖线把多个页面名拼在一个titles参数里一次请求最多能拿 50 个页面的内容能大幅减少请求次数。注意proprevisionsrvpropcontent的组合才是拿页面内容的正道titles不适合直接搭配actionparse做批量处理。2.3 跑通第一次请求从浏览器到命令行先在浏览器里访问下面这个 URL看看返回结果长什么样https://www.imfdb.org/api.php?actionquerylistsearchsrsearchJohn%20Wickformatjson你会看到一组嵌套的 JSON里面有searchinfo、search数组数组里每个对象包含title、pageid、snippet等字段。这就是 API 返回的标准结构了。顺手在请求参数里加一个formatversion2输出会更简洁数组字段名更短对新手来说更友好https://www.imfdb.org/api.php?actionquerylistsearchsrsearchJohn%20Wickformatjsonformatversion2命令行里用 curl 验证也很快curl -G https://www.imfdb.org/api.php \ --data-urlencode actionquery \ --data-urlencode listsearch \ --data-urlencode srsearchJohn Wick \ --data-urlencode formatjson \ --data-urlencode formatversion2一个值得养成的习惯所有请求都加上 User-Agent。MediaWiki 站点对缺失 UA 的请求会直接拒绝。建议把自己的项目名和联系方式写进去方便站点管理员在异常时联系你。3. 实操搭建一个影视道具检索小工具3.1 明确需求和整体流程先定一个小目标输入电影名输出这部电影里出现的道具型号列表。这是最典型的场景流程分成三步搜索关键词拿到规范页面名。抓取页面 wikitext。解析表格提取道具型号和对应角色。3.2 完整 Python 实现下面这份代码是我在类似场景里用 Python 写的简化版核心逻辑可以直接抄。先装依赖pip install requests然后写脚本import requests import re import json class IMFDBClient: API_URL https://www.imfdb.org/api.php def __init__(self, user_agentMyMovieTool/1.0 (contactexample.com)): self.headers {User-Agent: user_agent} self.session requests.Session() self.session.headers.update(self.headers) def search_pages(self, keyword): params { action: query, list: search, srsearch: keyword, format: json, formatversion: 2, } resp self.session.get(self.API_URL, paramsparams) resp.raise_for_status() data resp.json() return data.get(query, {}).get(search, []) def get_wikitext(self, page_title): params { action: parse, page: page_title, prop: wikitext, format: json, formatversion: 2, } resp self.session.get(self.API_URL, paramsparams) resp.raise_for_status() data resp.json() return data.get(parse, {}).get(wikitext, ) def parse_weapon_table(self, wikitext): # 找到以 {| 开头、|} 结尾的表格区块 tables re.findall(r\{\|(.*?)\|\}, wikitext, re.S) results [] for table in tables: rows re.findall(r\|-.*?\n(.*?)(?\n\|-|\n\|\}), table, re.S) for row in rows: cells re.findall(r\|{1,2}(.*?)(?\n\||\n\|\}), row, re.S) # 这里只提取第一列和第三列作为示例真实场景按需求调整 if len(cells) 3: model cells[1].strip() role cells[2].strip() # 去掉维基链接语法 [[xxx]] model re.sub(r\[\[(?:[^|\]]*\|)?([^\]])\]\], r\1, model) role re.sub(r\[\[(?:[^|\]]*\|)?([^\]])\]\], r\1, role) results.append({model: model, role: role}) return results if __name__ __main__: client IMFDBClient() keyword input(请输入电影名关键词: ) pages client.search_pages(keyword) if not pages: print(没有找到相关页面) exit() # 默认取第一个搜索结果 page_title pages[0][title] print(f定位到页面: {page_title}) wikitext client.get_wikitext(page_title) data client.parse_weapon_table(wikitext) print(f共解析到 {len(data)} 条道具记录:) for item in data[:20]: print(f {item[model]} - {item[role]})代码里重点解释几个容易出错的位置search_pages返回的title是规范页面名未必等于用户输入的关键词所以先搜索、再抓取是比“直接拿关键词当页名”稳得多的策略。parse_weapon_table里用的正则比较粗暴核心思路是把维基表格按行拆开、按单元格拆开。IMFDB 的表格列数不是完全统一的有的表有“备注”列有的没有真实场景中建议先打印几行 cell 数组看看结构再写解析规则。re.sub去掉[[xxx|显示名]]这种维基链接语法只保留显示名。这个细节不处理拿出来的数据就是一串带方括号的原始标记。3.3 批量扩展抓取整个分类下的全部条目单页检索做通了下一步就是批量抓取。假设你想把 IMFDB 上“电子游戏”分类下的所有页面都抓下来做分析核心是拿到分类成员列表然后循环抓内容。def get_category_members(self, category): params { action: query, generator: categorymembers, gcmtitle: fCategory:{category}, gcmtype: page, gcmlimit: 500, format: json, formatversion: 2, } resp self.session.get(self.API_URL, paramsparams) resp.raise_for_status() data resp.json() pages data.get(query, {}).get(pages, []) return [p[title] for p in pages if title in p]这段代码的逻辑很简单但有两点要特别注意。第一gcmlimit最大能设到 500但 MediaWiki API 对单次请求返回的最大结果数是有限制的如果分类下条目更多响应里会出现continue字段需要用gcmcontinue参数去翻页。写一个 while 循环只要响应里有continue就带上gcmcontinue继续请求直到没有为止。第二generatorcategorymembers返回的pages数组结构里每个元素直接有title字段配合formatversion2使用是最顺手的。但要注意这里拿到的“页面”有时候会包含分类页本身实际过滤时可以判断pageid是否为 0或者跳过标题以Category:开头的页。4. 高频问题与排查技巧实录4.1 请求被限流返回 429 状态码MediaWiki 站点的 API 对无 UA、高频率的请求会做限流表现就是 HTTP 429 或一段错误文本。解决方式从根源上就两条一是设置规范的 User-Agent二是控制并发度。我的做法是所有请求之间至少间隔 0.5 秒量特别大的抓取任务就加随机延迟到 1-2 秒。别嫌慢影视资料库的数据量不算大字段也不算多几千条页面按这个速度抓完也就一两个小时稳定比速度重要。如果只是自己在电脑上偶尔查一下压根不用担心限流问题。4.2 页面存在但返回空内容这种情况十有八九是碰到了重定向页。比如你搜“John Wick 2”实际页面名可能是“John Wick - Chapter 2”你用前者直接请求 parse 接口MediaWiki 会默认返回重定向页自身的内容而不是目标页的内容。此时要在解析参数里加一个redirects1actionparse pageJohn_Wick_2 redirects1 propwikitext formatjson加了这个参数API 会自动跳转到规范页面并返回那里的内容。另外一个更稳妥的办法是先用titles参数请求一次看响应里的normalized和redirects字段确认最终页面名是什么再用规范名抓内容。4.3 表格解析不稳定列数对不齐这是最让人头疼的问题。IMFDB 是人工编辑的不同编辑者写表格的习惯不完全一样有的给表格加了行号列有的在单元格里塞了多个换行有的用{{!}}模板代替竖线符号。正则解析在这种场景下属于“能用不够稳”的方案。经验是按三层递进思路处理第一层先用正则切出每个表格区块再切行、切单元格快速看数据结构。第二层如果正则效果差改用 MediaWiki API 直接返回解析后的 HTML用 BeautifulSoup 去解析table标签。HTML 表格结构比 wikitext 稳定适合列数量固定的页面。第三层如果个别页面实在太乱就不要用通用逻辑直接在代码里做“页面名白名单”对这少数页面单独写一条解析规则。我自己做完整项目时通常直接选第二层HTML 解析虽然代码量略大但容错性明显更好也方便提取图片地址。4.4 网络超时与断连问题IMFDB 服务器在国内直连的延迟不算低偶尔会有连接超时的情况。代码里务必给 requests 设置 timeout比如timeout(3, 10)同时做一个简单的重试机制。我常用的写法是失败后等待 3 秒重试最多三次三次还不行就跳过这个页面并记录日志最后统一人工补抓。这个处理方式能省下大量盯日志的时间。4.5 数据版权与使用边界最后说个容易被忽略的问题。IMFDB 的内容基于 MediaWiki 架构站点内文本大多以知识共享CC BY-SA协议发布截图素材的版权归原影视作品方所有。做技术开发时抓 JSON 数据没问题但如果要把解析出来的结构化数据和图片应用于公开项目、商业产品一定要仔细核对 IMFDB 站点的授权条款并妥善注明来源。大数据量、高频率的抓取行为不管对哪个站点来说都是一种压力能缓存就缓存能离线就离线。我自己会把抓下来的 wikitext 按页面名存成 JSON 文件二次分析直接用本地缓存不再向远端重复发请求这对双方都省事。5. 一点个人经验把 IMFDB 的数据结构化这个过程本身比想象中更锻炼人因为它逼着你同时处理接口调试、文本解析、异常兜底这三类问题任何一个项目做下来对 MediaWiki 生态的理解都会深不少。我自己的项目里到现在还留着一个习惯第一次抓取时不做任何数据清洗先把原始 wikitext 完整存档。这一步很多人觉得没必要真遇到线上解析代码改来改去、原有页面对不上的时候才会后悔原始数据没留底。原始数据在手随时可以重新解析不用去远端补请求。如果你只打算做一次性查询那用一个 curl 命令就够了如果你想长期维护一个影视道具资料库或周边工具建议尽早把请求封装、缓存层和异常记录做进代码里这套东西以后去抓其他 MediaWiki 站点也能直接复用。
返回列表