从维基百科文章(Python)中提取第一段

43

如何使用Python从维基百科文章中提取第一段?

例如,对于阿尔伯特·爱因斯坦,第一段应该是:

阿尔伯特·爱因斯坦(德语发音:/ˈælbərt ˈaɪnstaɪn/;1879年3月14日-1955年4月18日)是一位理论物理学家、哲学家和作家,被普遍认为是有史以来最具影响力和标志性的科学家和知识分子之一。作为德籍瑞士籍的诺贝尔奖获得者,爱因斯坦常被视为现代物理学之父[2]。他因“对理论物理学的贡献,特别是对光电效应定律的发现”而于1921年获得诺贝尔物理学奖[3]。


3
使用 urllib 获取网页,使用 BeautifulSoup 解析 HTML。虽然还有其他方法可以实现,但可以在 StackOverflow 上搜索这些方法。这个问题已经被讨论过很多次了。 - user225312
你想用什么标记语言呢?MediaWiki,HTML? - khachik
10个回答

54
我写了一个Python库,旨在使此过程变得非常简单。请到Github上查看。

安装它,运行以下命令:

$ pip install wikipedia

要获取文章的第一段,只需使用wikipedia.summary函数。

>>> import wikipedia
>>> print wikipedia.summary("Albert Einstein", sentences=2)

打印

阿尔伯特·爱因斯坦(/ˈælbərt ˈaɪnstaɪn/;德语:[ˈalbɐt ˈaɪnʃtaɪn](听取);1879年3月14日 - 1955年4月18日)是一位出生在德国的理论物理学家,发展了广义相对论,是现代物理学的两大支柱之一(另一个支柱是量子力学)。虽然他以质能方程E = mc2而闻名于世(被称为“世界上最著名的方程式”),但他因“为理论物理学作出的贡献,并特别是为发现光电效应定律”而获得了1921年的诺贝尔物理学奖。

至于它是如何工作的,wikipedia向MediaWiki API的Mobile Frontend Extension发送请求,后者返回维基百科文章的移动友好版本。具体而言,通过传递参数prop=extracts&exsectionformat=plain,MediaWiki服务器将解析Wikitext并返回您请求的文章的纯文本摘要,包括整个页面文本。它还接受参数excharsexsentences,这不足为奇地限制了API返回的字符数和句子数。


3
图书馆设计非常出色,而且相当易于使用!干得好。 :) - Kitchi
prop=extracts 在2014年从MobileFrontend中分离出来,成为了一个独立的TextExtracts扩展,但API调用保持不变。 - skierpage
这个不错的库值得一加赞。 我正在开发一个大型项目,需要调用大约6k个页面。您有什么关于如何在这种情况下使用维基百科的建议吗?我的意思是,是否有更好的方法来避免手动编写页面标题列表并将其提供给wikipedia.page()函数呢? - Elm662

45

我之前写了两个类来获取维基百科文章的纯文本。我知道它们不是最好的解决方案,但你可以根据自己的需求进行适当的调整:

    wikipedia.py
    wiki2plain.py

你可以这样使用它:

from wikipedia import Wikipedia
from wiki2plain import Wiki2Plain

lang = 'simple'
wiki = Wikipedia(lang)

try:
    raw = wiki.article('Uruguay')
except:
    raw = None

if raw:
    wiki2plain = Wiki2Plain(raw)
    content = wiki2plain.text

1
在 http://pastebin.com/FVDxLWNG 中,#REDIRECT 对于 it.wikipedia.org 不起作用,必须翻译成意大利语,如 #RINVIA。我怀疑 #REDIRECT 只适用于英语。 - Alessandro Jacopson
@joksnet,我认为使用您自定义的类可能会产生误导,因为名称与wikipedia的Python API有些冲突。 - Sumax

14

维基百科运行一个MediaWiki扩展,提供了一个API模块来实现这个功能。 TextExtracts 实现了 action=query&prop=extracts选项,可以返回前N句话和/或简介,以HTML或纯文本形式。

以下是您需要调用的API,请尝试一下: https://en.wikipedia.org/w/api.php?action=query&prop=extracts&titles=Albert%20Einstein&exintro=&exsentences=2&explaintext=&redirects=&formatversion=2

  • action=query&prop=extracts 请求信息
  • (ex)sentences=2, (ex)intro=, (ex)plaintext 是向该模块请求两个句子的纯文本版本的简介;为获取HTML版本则不需要(ex)plaintext参数。
  • redirects=(设置为true)因此如果您请求“titles=Einstein”,则会获得阿尔伯特·爱因斯坦页面的信息。
  • formatversion=2 可以获得UTF-8格式的更清晰的输出。

有各种库可以封装调用MediaWiki操作API,例如DGund回答中的库,但自己调用API并不太难。

搜索结果中的页面信息 讨论了获取文本摘录以及文章描述和引导图像。


11

我所做的是这样的:

import urllib
import urllib2
from BeautifulSoup import BeautifulSoup

article= "Albert Einstein"
article = urllib.quote(article)

opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')] #wikipedia needs this

resource = opener.open("http://en.wikipedia.org/wiki/" + article)
data = resource.read()
resource.close()
soup = BeautifulSoup(data)
print soup.find('div',id="bodyContent").p

注意:Python 3.x用户会发现urllib2已经被弃用。urllib应该是唯一解析和处理“url”的类。 - Sumax

5
相对较新的 REST API 具有一个完美的 summary 方法,非常适合此用途,并且执行了其他答案中提到的许多操作(例如删除wikicode)。它甚至包括相关的图片和地理坐标信息。
使用可爱的 requests 模块和 Python 3:
import requests
r = requests.get("https://en.wikipedia.org/api/rest_v1/page/summary/Amsterdam")
page = r.json()
print(page["extract"]) # Returns 'Amsterdam is the capital and...'

2

正如其他人所说,一种方法是使用维基媒体API和urllib或urllib2。下面的代码片段是我用来提取所谓的“引导”部分(包括文章摘要和信息框)的一部分。这将检查返回的文本是否是重定向而不是实际内容,还可以让您跳过信息框(如果存在)。在我的情况下,我使用了不同的代码来提取和格式化信息框。

contentBaseURL='http://en.wikipedia.org/w/index.php?title='

def getContent(title):
    URL=contentBaseURL+title+'&action=raw&section=0'
    f=urllib.urlopen(URL)
    rawContent=f.read()
    return rawContent

infoboxPresent = 0
# Check if a redirect was returned.  If so, go to the redirection target
    if rawContent.find('#REDIRECT') == 0:
        rawContent = getFullContent(title)
        # extract the redirection title
        # Extract and format the Infobox
        redirectStart=rawContent.find('#REDIRECT[[')+11   
        count = 0
        redirectEnd = 0
        for i, char in enumerate(rawContent[redirectStart:-1]):
            if char == "[": count += 1
            if char == "]}":
                count -= 1
                if count == 0:
                    redirectEnd = i+redirectStart+1
                    break
        redirectTitle = rawContent[redirectStart:redirectEnd]
        print 'redirectTitle is: ',redirectTitle
        rawContent = getContent(redirectTitle)

    # Skip the Infobox
    infoboxStart=rawContent.find("{{Infobox")   #Actually starts at the double {'s before "Infobox"
    count = 0
    infoboxEnd = 0
    for i, char in enumerate(rawContent[infoboxStart:-1]):
        if char == "{": count += 1
        if char == "}":
            count -= 1
            if count == 0:
                infoboxEnd = i+infoboxStart+1
                break

    if infoboxEnd <> 0:
        rawContent = rawContent[infoboxEnd:]

你将会得到包括维基标记的原始文本,因此你需要进行一些清理。如果你只想要第一个段落而不是整个第一节,可以查找第一个换行符。


2

可能是维基百科正在阻止某些用户代理 :) - dzen

2

0
尝试使用pattern
pip install pattern

from pattern.web import Wikipedia
article = Wikipedia(language="af").search('Kaapstad', throttle=10)
print article.string

无法在Python3.6中使用'pip3 install pattern'... SyntaxError: Missing parentheses in call to 'print' - mosh
很遗憾,目前看来这个模式只适用于Python 2。 - Superdooperhero

0
尝试使用urllib来获取网站,再使用BeautifulSouplxml来解析数据的组合。

我很高兴能够手动解析HTML。嘿嘿,耶! - dzen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接