如何通过MediaWiki API获取维基百科页面中的信息表格
嘿,我来帮你解决这个问题!你之前用prop=extracts确实只能拿到页面的文本提取,没法获取右侧那个信息框(infobox)里的结构化数据——要搞定这个,咱们得换个API调用方式,再配合专门的工具来解析维基百科的模板内容。
核心思路
维基百科的歌曲信息框是用{{Infobox song}}这个MediaWiki模板构建的,所以咱们需要先拿到页面的原始wikitext内容,再从中解析这个模板里的字段值。这种方式比直接解析HTML要可靠得多,因为模板结构相对稳定。
具体步骤&代码示例
1. 安装必要的库
咱们用requests发API请求,再用mwparserfromhell这个专门解析MediaWiki wikitext的库来处理模板——它比手写正则靠谱多了,能轻松处理各种模板格式的变化(比如换行、嵌套标记)。
先安装依赖:
pip install mwparserfromhell requests
2. 编写代码提取信息
下面的代码会调用API拿到页面wikitext,然后解析出你需要的专辑、发行日期、创作者等信息:
import requests import mwparserfromhell # 配置API请求参数 api_params = { "action": "query", "titles": "Zombie_(song)", "prop": "revisions", "rvprop": "content", "rvslots": "main", "format": "json", "formatversion": 2 } # 发送请求并解析响应 response = requests.get("https://en.wikipedia.org/w/api.php", params=api_params) response_data = response.json() # 获取页面的原始wikitext target_page = response_data["query"]["pages"][0] if "revisions" in target_page: page_wikitext = target_page["revisions"][0]["slots"]["main"]["content"] # 解析wikitext,定位到歌曲信息框模板 parsed_content = mwparserfromhell.parse(page_wikitext) song_infobox = parsed_content.filter_templates(matches="Infobox song")[0] # 提取你需要的字段 extracted_info = {} desired_fields = ["album", "released", "songwriter", "producer"] for field in desired_fields: try: # strip_code()会去掉wikitext的格式标记(比如链接、斜体),只保留纯文本 field_value = song_infobox.get(field).value.strip_code() extracted_info[field] = field_value.strip() except ValueError: # 如果字段不存在,返回N/A extracted_info[field] = "N/A" # 打印结果 print("提取到的《Zombie》歌曲信息:") for key, value in extracted_info.items(): print(f"- {key.title()}: {value}") else: print("抱歉,无法获取页面内容,请检查请求参数或网络连接。")
为什么不用HTML解析?
你也可以用action=parseAPI获取页面的HTML,然后用BeautifulSoup解析infobox表格,但这种方法容易因为页面HTML结构的变化失效——维基百科的模板结构相对稳定,解析wikitext的方式更长久可靠。
备选方案:不用第三方库(不推荐)
如果不想安装mwparserfromhell,也可以用正则表达式匹配wikitext里的infobox,但这种方法容错性差,遇到模板格式变化(比如换行、空格)就会出错,示例代码如下:
import re # 假设已经拿到了page_wikitext infobox_match = re.search(r"{{Infobox song([\s\S]+?)}}", page_wikitext) if infobox_match: infobox_content = infobox_match.group(1) # 提取专辑信息 album_match = re.search(r"\| *album *=(.*?)(?=\n\||\n}})", infobox_content, re.DOTALL) if album_match: album = album_match.group(1).strip() print(f"专辑:{album}")
内容的提问来源于stack exchange,提问作者Matthew Oujiri




