如何使用 Python 3 和 Beautiful Soup 获取 Wikipedia 文章的文本?

Posted

技术标签:

【中文标题】如何使用 Python 3 和 Beautiful Soup 获取 Wikipedia 文章的文本?【英文标题】:How can I get a Wikipedia article's text using Python 3 with Beautiful Soup? 【发布时间】:2019-05-17 04:41:27 【问题描述】:

我有这个用 Python 3 编写的脚本:

response = simple_get("https://en.wikipedia.org/wiki/Mathematics")
result = 
result["url"] = url
if response is not None:
    html = BeautifulSoup(response, 'html.parser')
    title = html.select("#firstHeading")[0].text

如您所见,我可以从文章中获得标题,但我不知道如何将文本从“数学(来自希腊语 μά...”)获取到目录...

【问题讨论】:

【参考方案1】:

有一种更简单的方法可以从***获取信息 - Wikipedia API

有this Python wrapper,它只允许您在几行代码中完成零 HTML 解析:

import wikipediaapi

wiki_wiki = wikipediaapi.Wikipedia('en')

page = wiki_wiki.page('Mathematics')
print(page.summary)

打印:

数学(来自希腊语 μάθημα máthēma,“知识、学习、学习”) 包括对数量、结构、空间和 改变……(特意省略)

而且,一般来说,如果有可用的直接 API,请尽量避免屏幕抓取。

【讨论】:

【参考方案2】:

选择<p> 标签。有 52 个元素。不确定你是否想要整个东西,但你可以遍历这些标签来尽可能地存储它。我只是选择打印它们中的每一个来显示输出。

import bs4
import requests


response = requests.get("https://en.wikipedia.org/wiki/Mathematics")

if response is not None:
    html = bs4.BeautifulSoup(response.text, 'html.parser')

    title = html.select("#firstHeading")[0].text
    paragraphs = html.select("p")
    for para in paragraphs:
        print (para.text)

    # just grab the text up to contents as stated in question
    intro = '\n'.join([ para.text for para in paragraphs[0:5]])
    print (intro)

【讨论】:

if response is not None 可以重写为if response。另外,由于将来内容可能会发生变化,我建议获取整个 div,只阅读 p 并在到达带有“t​​oclimit-3”类的 div 时停止 @PinoSan 我认为明确检查 None 并没有什么坏处。例如bool('' is not None)bool('') 不同。但是,在这种情况下,None 检查是完全没有必要的,因为response 将始终是requests.models.Response 对象。如果请求失败,将引发异常。 @t.m.adam 你说的是真的,但正如你所说,响应不是字符串。所以你只是想检查它是一个有效的对象,而不是一个空字符串,None 或一个空字典,......关于异常,我同意我们应该检查异常以防网络错误,但我们也应该检查状态代码为 200 @PinoSan 当然,我也更喜欢if response 风格,但你知道,"Explicit is better than implicit."。 if response 的问题是它可能会产生奇怪的错误,难以调试。但是,是的,在大多数情况下,一个简单的布尔检查就足够了。 仅仅因为你可以抓取页面,并不意味着你应该。 Wikipedia API 具有 python 包,允许轻松直接地访问文章,而无需在网站上过度加载或额外工作。【参考方案3】:

使用库wikipedia

import wikipedia
#print(wikipedia.summary("Mathematics"))
#wikipedia.search("Mathematics")
print(wikipedia.page("Mathematics").content)

【讨论】:

我会改用wikipediaapiwikipedia 模块似乎没有维护。不过,两者都会以类似的方式完成工作。【参考方案4】:

您可以使用lxml 库获得所需的输出,如下所示。

import requests
from lxml.html import fromstring

url = "https://en.wikipedia.org/wiki/Mathematics"

res = requests.get(url)
source = fromstring(res.content)
paragraph = '\n'.join([item.text_content() for item in source.xpath('//p[following::h2[2][span="History"]]')])
print(paragraph)

使用BeautifulSoup

from bs4 import BeautifulSoup
import requests

res = requests.get("https://en.wikipedia.org/wiki/Mathematics")
soup = BeautifulSoup(res.text, 'html.parser')
for item in soup.find_all("p"):
    if item.text.startswith("The history"):break
    print(item.text)

【讨论】:

【参考方案5】:

您似乎想要的是没有周围导航元素的 (HTML) 页面内容。正如我在this earlier answer from 2013 中所描述的,有(至少)两种方法可以得到它:

在您的情况下,最简单的方法可能是在 URL 中包含参数 action=render,如 https://en.wikipedia.org/wiki/Mathematics?action=render。这将只为您提供内容 HTML,而不是其他内容。

您也可以通过MediaWiki API获取页面内容,如https://en.wikipedia.org/w/api.php?format=xml&action=parse&page=Mathematics。

使用 API 的优势在于它还可以为您提供a lot of other information 关于您可能觉得有用的页面的信息。例如,如果您想要一个通常显示在页面侧边栏中的跨语言链接列表,或者通常显示在内容区域下方的类别,您可以从 API 中获取这些内容,如下所示:

https://en.wikipedia.org/w/api.php?format=xml&action=parse&page=Mathematics&prop=langlinks|categories

(若要获取相同请求的页面内容,请使用prop=langlinks|categories|text。)

有几个Python libraries for using the MediaWiki API 可以自动化使用它的一些基本细节,尽管它们支持的功能集可能会有所不同。也就是说,直接从您的代码中使用 API 而无需中间的库也是完全可能的。

【讨论】:

【参考方案6】:

要获得正确的函数使用方法,您可以获取 Wikipedia 提供的 JSON API

from urllib.request import urlopen
from urllib.parse import urlencode
from json import loads


def getJSON(page):
    params = urlencode(
        'format': 'json',
        'action': 'parse',
        'prop': 'text',
        'redirects' : 'true',
        'page': page)
    API = "https://en.wikipedia.org/w/api.php"
    response = urlopen(API + "?" + params)
    return response.read().decode('utf-8')


def getRawPage(page):
    parsed = loads(getJSON(page))
    try:
        title = parsed['parse']['title']
        content = parsed['parse']['text']['*']
        return title, content
    except KeyError:
        # The page doesn't exist
        return None, None

title, content = getRawPage("Mathematics")

然后你可以用任何你想提取你需要的库来解析它:)

【讨论】:

【参考方案7】:

我使用这个:通过 'idx' 我可以确定我想阅读哪个段落。

from from bs4 import BeautifulSoup
import requests

res = requests.get("https://de.wikipedia.org/wiki/Pferde")
soup = BeautifulSoup(res.text, 'html.parser')
for idx, item in enumerate(soup.find_all("p")):
    if idx == 1:
        break
print(item.text)

【讨论】:

那么页面里面的第一段就是文章的内容?我对此表示怀疑。 不,这只是第一段。您可以使用 idx == 来确定要查看的段落。 我知道,但除了它可能会改变之外,从文档中提取或多或少随机元素并不是最好的选择。 @shaedrich 我想再次解释一下。重点是遍历各个章节。例如,在类似 Alexa 版本的 Dialog 中:询问“什么是马”。在这种情况下,您会收到很多文本。在对话中你现在可以说:“阅读更多”。或者跳过这一章。我希望你现在明白这种迭代的可能性是多么有用。谢谢。 对不起,不是真的。

以上是关于如何使用 Python 3 和 Beautiful Soup 获取 Wikipedia 文章的文本?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Python 和 Beautiful Soup 从框架中抓取信息

如何在 Beautiful Soup 4 (Python) 中使用搜索栏

Python 3.6 Beautiful Soup - 在网页抓取期间无法获取嵌入式视频 URL

[Python3网络爬虫开发实战] 1.3.2-Beautiful Soup的安装

使用python beautiful soup或html模块的电子邮件刮刀

Python 3 Beautiful Soup 用冒号查找标签