【问题标题】:How can I get a Wikipedia article's text using Python 3 with Beautiful Soup?如何使用 Python 3 和 Beautiful Soup 获取 Wikipedia 文章的文本?
【发布时间】: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

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

【问题讨论】:

    标签: python html web-scraping beautifulsoup wikipedia


    【解决方案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 中所描述的,有(至少)两种方法可以得到它:

        使用 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 中:询问“什么是马”。在这种情况下,您会收到很多文本。在对话中你现在可以说:“阅读更多”。或者跳过这一章。我希望你现在明白这种迭代的可能性是多么有用。谢谢。
            • 对不起,不是真的。
            猜你喜欢
            • 2021-01-23
            • 1970-01-01
            • 2010-09-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-17
            相关资源
            最近更新 更多