Python 从维基百科解析出生和死亡日期?
我正试图编写一个python程序,可以在维基百科上搜索人们的出生和死亡日期 例如,阿尔伯特·爱因斯坦出生于1879年3月14日;死亡日期:1955年4月18日 我从 这就行了Python 从维基百科解析出生和死亡日期?,python,mediawiki,wikipedia,wikipedia-api,mediawiki-api,Python,Mediawiki,Wikipedia,Wikipedia Api,Mediawiki Api,我正试图编写一个python程序,可以在维基百科上搜索人们的出生和死亡日期 例如,阿尔伯特·爱因斯坦出生于1879年3月14日;死亡日期:1955年4月18日 我从 这就行了page2是Albert Einstein维基百科页面部分的xml表示 我看了本教程,现在我有了xml格式的页面,但是我不明白如何从xml中获取我想要的信息(出生和死亡日期)。我觉得我必须离得很近,但我不知道如何从这里开始 编辑 经过几次回复,我安装了BeautifulSoup。我现在正处于打印的阶段: import Bea
page2
是Albert Einstein维基百科页面部分的xml表示
我看了本教程,现在我有了xml格式的页面,但是我不明白如何从xml中获取我想要的信息(出生和死亡日期)。我觉得我必须离得很近,但我不知道如何从这里开始
编辑
经过几次回复,我安装了BeautifulSoup。我现在正处于打印的阶段:
import BeautifulSoup as BS
soup = BS.BeautifulSoup(page2)
print soup.getText()
{{Infobox scientist
| name = Albert Einstein
| image = Einstein 1921 portrait2.jpg
| caption = Albert Einstein in 1921
| birth_date = {{Birth date|df=yes|1879|3|14}}
| birth_place = [[Ulm]], [[Kingdom of Württemberg]], [[German Empire]]
| death_date = {{Death date and age|df=yes|1955|4|18|1879|3|14}}
| death_place = [[Princeton, New Jersey|Princeton]], New Jersey, United States
| spouse = [[Mileva Marić]]&nbsp;(1903–1919)<br>{{nowrap|[[Elsa Löwenthal]]&nbsp;(1919–1936)}}
| residence = Germany, Italy, Switzerland, Austria, Belgium, United Kingdom, United States
| citizenship = {{Plainlist|
* [[Kingdom of Württemberg|Württemberg/Germany]] (1879–1896)
* [[Statelessness|Stateless]] (1896–1901)
* [[Switzerland]] (1901–1955)
* [[Austria–Hungary|Austria]] (1911–1912)
* [[German Empire|Germany]] (1914–1933)
* United States (1940–1955)
}}
所以,更接近了,但我仍然不知道如何以这种格式返回死亡日期。除非我开始用
re
解析东西?我可以这样做,但我觉得我会用错误的工具来做这项工作。 < P>你可以考虑使用一个库,例如或解析响应HTML/XML。
您可能还想看一看,它有一个更干净的用于发出请求的API
以下是使用
请求
、美化组
和重新
的工作代码,可以说不是这里的最佳解决方案,但它非常灵活,可以扩展以解决类似问题:
import re
import requests
from bs4 import BeautifulSoup
url = 'http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&rvsection=0&titles=Albert_Einstein&format=xml'
res = requests.get(url)
soup = BeautifulSoup(res.text, "xml")
birth_re = re.search(r'(Birth date(.*?)}})', soup.revisions.getText())
birth_data = birth_re.group(0).split('|')
birth_year = birth_data[2]
birth_month = birth_data[3]
birth_day = birth_data[4]
death_re = re.search(r'(Death date(.*?)}})', soup.revisions.getText())
death_data = death_re.group(0).split('|')
death_year = death_data[2]
death_month = death_data[3]
death_day = death_data[4]
根据@JBernardo的建议,使用JSON数据和
mwparserfromhell
,对于这个特定用例,一个更好的答案是:
import requests
import mwparserfromhell
url = 'http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&rvsection=0&titles=Albert_Einstein&format=json'
res = requests.get(url)
text = res.json["query"]["pages"].values()[0]["revisions"][0]["*"]
wiki = mwparserfromhell.parse(text)
birth_data = wiki.filter_templates(matches="Birth date")[0]
birth_year = birth_data.get(1).value
birth_month = birth_data.get(2).value
birth_day = birth_data.get(3).value
death_data = wiki.filter_templates(matches="Death date")[0]
death_year = death_data.get(1).value
death_month = death_data.get(2).value
death_day = death_data.get(3).value
首先:维基百科API允许使用JSON而不是XML,这将使事情变得更加简单 Second:根本不需要使用HTML/XML解析器(内容不是HTML,容器也不需要)。您需要解析的是JSON的“revisions”标记中的Wiki格式 检查一些Wiki解析器
这里让人困惑的是,API允许您请求某种格式(XML或JSON),但这只是您想要解析的实际格式文本的容器: 这个:
{{出生日期| df=yes | 1879 | 3 | 14}
有了上面链接中提供的一个解析器,您就可以做到这一点。首先,使用。它允许您通过高级抽象界面查询文章文本、模板参数等。其次,我将使用
Persondata
模板(请看文章末尾)。此外,从长远来看,您可能会感兴趣,这将需要几个月的时间来介绍,但这将使Wikipedia文章中的大多数元数据易于查询。现在不推荐使用persondata
模板,您应该改为访问Wikidata。看见我之前(现在已弃用)在2012年的回答如下:
您应该做的是解析大多数传记文章中的
模板。有,以你现有的知识和其他有用的答案,我相信你可以做到这一点
2019年的一个替代方案是使用Wikidata API,该API以结构化格式公开诸如出生和死亡日期等传记数据,无需任何自定义解析器即可轻松使用。许多维基百科文章的信息都依赖于维基百科数据,因此在许多情况下,这与您使用维基百科数据的情况相同 例如,查看并搜索“出生日期”和“死亡日期”,您会发现它们与维基百科中的相同。Wikidata中的每个实体都有一个“声明”列表,即“属性”和“值”对。要知道爱因斯坦是什么时候出生和去世的,我们只需要在语句列表中搜索适当的属性,在本例中,以及。要通过编程实现这一点,最好以json的形式访问实体,您可以使用以下url结构: 作为一个例子,以下是关于爱因斯坦的声明
P569
:
"P569": [
{
"mainsnak": {
"property": "P569",
"datavalue": {
"value": {
"time": "+1879-03-14T00:00:00Z",
"timezone": 0,
"before": 0,
"after": 0,
"precision": 11,
"calendarmodel": "http://www.wikidata.org/entity/Q1985727"
},
"type": "time"
},
"datatype": "time"
},
"type": "statement",
您可以在中了解有关访问Wikidata的更多信息,更具体地了解如何在中构建日期。我遇到了这个问题,非常感谢在中提供的所有有用信息,但需要一些综合才能找到有效的解决方案。在这里分享,以防对其他人有用。该代码也适用于那些希望分叉/改进它的人 特别是,这里没有太多的错误处理方法
import csv
from datetime import datetime
import json
import requests
from dateutil import parser
def id_for_page(page):
"""Uses the wikipedia api to find the wikidata id for a page"""
api = "https://en.wikipedia.org/w/api.php"
query = "?action=query&prop=pageprops&titles=%s&format=json"
slug = page.split('/')[-1]
response = json.loads(requests.get(api + query % slug).content)
# Assume we got 1 page result and it is correct.
page_info = list(response['query']['pages'].values())[0]
return page_info['pageprops']['wikibase_item']
def lifespan_for_id(wikidata_id):
"""Uses the wikidata API to retrieve wikidata for the given id."""
data_url = "https://www.wikidata.org/wiki/Special:EntityData/%s.json"
page = json.loads(requests.get(data_url % wikidata_id).content)
claims = list(page['entities'].values())[0]['claims']
# P569 (birth) and P570 (death) ... not everyone has died yet.
return [get_claim_as_time(claims, cid) for cid in ['P569', 'P570']]
def get_claim_as_time(claims, claim_id):
"""Helper function to work with data returned from wikidata api"""
try:
claim = claims[claim_id][0]['mainsnak']['datavalue']
assert claim['type'] == 'time', "Expecting time data type"
# dateparser chokes on leading '+', thanks wikidata.
return parser.parse(claim['value']['time'][1:])
except KeyError as e:
print(e)
return None
def main():
page = 'https://en.wikipedia.org/wiki/Albert_Einstein'
# 1. use the wikipedia api to find the wikidata id for this page
wikidata_id = id_for_page(page)
# 2. use the wikidata id to get the birth and death dates
span = lifespan_for_id(wikidata_id)
for label, dt in zip(["birth", "death"], span):
print(label, " = ", datetime.strftime(dt, "%b %d, %Y"))
您是否检查了数据以查看HTML/XML解析器是否有帮助?提示:会的not@JBernardo没错,内容在同一个XML标记中。虽然JSON格式似乎也有同样的问题。我想你建议的解析器之一会解析标签中的数据?@KayZhu那么你意识到他想要解析的真正数据是Wiki格式吗?JSON的使用是为了使访问Wiki数据更容易(因为JSON比XML简单得多)@JBernardo是的,你是对的,虽然链接中的解析器可以很好地处理这两种情况。XML解析器不会进一步帮助你。阅读JBernardo所说的:获取json格式的数据,并使用专用的MW解析器。我已经附上了完整的代码,使用或不使用
re
对其进行解析。请不要试图通过您的用户代理模拟浏览器。根据,您应该使用“带有联系信息的信息用户代理字符串”。好的,这样我就可以将其作为JSON阅读:infle=opener.open('http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&rvsection=0&titles=Albert_Einstein&format=json)
查看链接到的Wiki解析器,我看到很多是XML/HTML,但没有列出JSON。有推荐的吗?@JBWhitmorejson
模块随Python提供。它只是您想要解析的真实数据的容器。此数据不是XML、HTML或JSON格式。它在某个特定的Wiki中format@JBWhitmore您想要解析这类数据:{{Birth date | df=yes | 1879 | 3 | 14}
和
import csv
from datetime import datetime
import json
import requests
from dateutil import parser
def id_for_page(page):
"""Uses the wikipedia api to find the wikidata id for a page"""
api = "https://en.wikipedia.org/w/api.php"
query = "?action=query&prop=pageprops&titles=%s&format=json"
slug = page.split('/')[-1]
response = json.loads(requests.get(api + query % slug).content)
# Assume we got 1 page result and it is correct.
page_info = list(response['query']['pages'].values())[0]
return page_info['pageprops']['wikibase_item']
def lifespan_for_id(wikidata_id):
"""Uses the wikidata API to retrieve wikidata for the given id."""
data_url = "https://www.wikidata.org/wiki/Special:EntityData/%s.json"
page = json.loads(requests.get(data_url % wikidata_id).content)
claims = list(page['entities'].values())[0]['claims']
# P569 (birth) and P570 (death) ... not everyone has died yet.
return [get_claim_as_time(claims, cid) for cid in ['P569', 'P570']]
def get_claim_as_time(claims, claim_id):
"""Helper function to work with data returned from wikidata api"""
try:
claim = claims[claim_id][0]['mainsnak']['datavalue']
assert claim['type'] == 'time', "Expecting time data type"
# dateparser chokes on leading '+', thanks wikidata.
return parser.parse(claim['value']['time'][1:])
except KeyError as e:
print(e)
return None
def main():
page = 'https://en.wikipedia.org/wiki/Albert_Einstein'
# 1. use the wikipedia api to find the wikidata id for this page
wikidata_id = id_for_page(page)
# 2. use the wikidata id to get the birth and death dates
span = lifespan_for_id(wikidata_id)
for label, dt in zip(["birth", "death"], span):
print(label, " = ", datetime.strftime(dt, "%b %d, %Y"))