【问题标题】:How can I parse a Wikipedia XML dump with Python?如何使用 Python 解析 Wikipedia XML 转储?
【发布时间】:2019-11-15 05:15:06
【问题描述】:

我有:

import xml.etree.ElementTree as ET


def strip_tag_name(t):
    t = elem.tag
    idx = k = t.rfind("}")
    if idx != -1:
        t = t[idx + 1:]
    return t


events = ("start", "end")

title = None
for event, elem in ET.iterparse('data/enwiki-20190620-pages-articles-multistream.xml', events=events):
    tname = strip_tag_name(elem.tag)

    if event == 'end':
        if tname == 'title':
            title = elem.text
        elif tname == 'page':
            print(title, elem.text)

这似乎给了标题就好了,但页面text 似乎总是空白。我错过了什么?

我无法打开文件(它很大),但我认为这是一个准确的 sn-p:

<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
  <siteinfo>
    <sitename>Wikipedia</sitename>
    <dbname>enwiki</dbname>
    <base>https://en.wikipedia.org/wiki/Main_Page</base>
    <generator>MediaWiki 1.29.0-wmf.12</generator>
    <case>first-letter</case>
    <namespaces>
      ...
    </namespaces>
  </siteinfo>
  <page>
    <title>AccessibleComputing</title>
    <ns>0</ns>
    <id>10</id>
    <redirect title="Computer accessibility" />
    <revision>
      <id>631144794</id>
      <parentid>381202555</parentid>
      <timestamp>2014-10-26T04:50:23Z</timestamp>
      <contributor>
        <username>Paine Ellsworth</username>
        <id>9092818</id>
      </contributor>
      <comment>add [[WP:RCAT|rcat]]s</comment>
      <model>wikitext</model>
      <format>text/x-wiki</format>
      <text xml:space="preserve">#REDIRECT [[Computer accessibility]]

\{\{Redr|move|from CamelCase|up\}\}</text>
      <sha1>4ro7vvppa5kmm0o1egfjztzcwd0vabw</sha1>
    </revision>
  </page>
  <page>
    <title>Anarchism</title>
    <ns>0</ns>
    <id>12</id>
    <revision>
      <id>766348469</id>
      <parentid>766047928</parentid>
      <timestamp>2017-02-19T18:08:07Z</timestamp>
      <contributor>
        <username>GreenC bot</username>
        <id>27823944</id>
      </contributor>
      <minor />
      <comment>Reformat 1 archive link. [[User:Green Cardamom/WaybackMedic_2.1|Wayback Medic 2.1]]</comment>
      <model>wikitext</model>
      <format>text/x-wiki</format>
      <text xml:space="preserve">
      ...
      </text>
    </revision>
  </page>
</mediawiki>

【问题讨论】:

  • 关于标签的解析可能有问题,分享一个 XML 的 sn-p 供人们查看
  • 完成 - 共享一个 XML sn-p
  • 你的 sn-p 不会解析。
  • &lt;page&gt; 元素的文本内容只是空格。我想你想要&lt;text&gt; 元素的文本?

标签: python xpath elementtree


【解决方案1】:

最好的方法是使用MWXML python 包,它是Mediawiki Utilities 的一部分(可与pip3 install mwxml 一起安装)。 MWXML 旨在解决这一特定问题并被广泛使用。该软件由Wikimedia Foundation 的研究人员创建,由基金会内外的一组研究人员维护。

这是一个改编自 an example notebook distributed with the library 的代码示例,它打印出页面 ID、修订 ID、时间戳和文本长度:

import mwxml
import glob

paths = glob.glob('/public/dumps/public/nlwiki/20151202/nlwiki-20151202-pages-meta-history*.xml*.bz2')

def process_dump(dump, path):
  for page in dump:
    for revision in page:
        yield page.id, revision.id, revision.timestamp, len(revision.text)

for page_id, rev_id, rev_timestamp, rev_textlength in mwxml.map(process_dump, paths):
    print("\t".join(str(v) for v in [page_id, rev_id, rev_timestamp, rev_textlength]))

从中改编的full example 报告每个修订版中添加和删除的图像链接的数量。它有完整的文档,但仅包含 25 行代码。

【讨论】:

    【解决方案2】:

    要获取维基百科文章,您需要访问&lt;text&gt; 元素的text 属性的内容,而不是&lt;page&gt; 元素。

    这是您的代码的更正版本:

    import xml.etree.ElementTree as ET
    
    
    def strip_tag_name(t):
        t = elem.tag
        idx = k = t.rfind("}")
        if idx != -1:
            t = t[idx + 1:]
        return t
    
    
    events = ("start", "end")
    
    title = None
    for event, elem in ET.iterparse('data/enwiki-20190620-pages-articles-multistream.xml', events=events):
        tname = strip_tag_name(elem.tag)
    
        if event == 'end':
            if tname == 'title':
                title = elem.text
            elif tname == 'text':
                print(title, elem.text)
    
        elem.clear()
    

    由于 Wikipedia 转储相当大,请不要忘记 for 循环末尾的 elem.clear()

    mzjn answers 中所述,&lt;page&gt; 元素的text 属性的内容只是空格。

    【讨论】:

      【解决方案3】:

      文本是指元素标签之间的文本(即&lt;tag&gt;text&lt;/tag&gt;),而不是所有子元素。因此,如果是 title 元素,则具有:

      <title>AccessibleComputing</title>
      

      标签之间的文本是AccessibleComputing

      对于page 元素,定义的唯一文本是'\n ',还有其他子元素(见下文),包括title 元素:

      <page>
          <title>Anarchism</title>
          <ns>0</ns>
          <id>12</id>
          ... 
      </page>
      

      w3schools page查看更多详情

      如果你想解析文件,我建议使用findall 方法:

      from lxml import etree
      from lxml.etree import tostring
      
      tree = etree.parse('data/enwiki-20190620-pages-articles-multistream.xml')
      root = tree.getroot()
      # iterate through all the titles
      for title in root.findall(".//title", namespaces=root.nsmap):
          print(tostring(title))
          print(title.text)
      
      

      生成此输出:

      b'<title xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">AccessibleComputing</title>\n    '
      AccessibleComputing
      b'<title xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Anarchism</title>\n    '
      Anarchism
      
      

      xpath 方法:

      nsmap = root.nsmap
      nsmap['x'] = root.nsmap[None]
      nsmap.pop(None)
      # iterate through all the pages
      for page in root.findall(".//x:page", namespaces=nsmap):
          print(page)
          print(repr(page.text)) # which prints '\n    '
          print('number of children: %i' % len(page.getchildren()))
      
      

      输出是:

      <Element {http://www.mediawiki.org/xml/export-0.10/}page at 0x7ff75cc610c8>
      '\n    '
      number of children: 5
      <Element {http://www.mediawiki.org/xml/export-0.10/}page at 0x7ff75cc71bc8>
      '\n    '
      number of children: 5
      

      详情请见lxml tutorial

      【讨论】:

        【解决方案4】:

        对于 XML 解析,我使用来自 PYPI 的包 untangle,它提供了完整的文档视图。那么你有:

        import untangle
        
        doc = untangle.parse('data/enwiki-20190620-pages-articles-multistream.xml')
        for page in doc.mediawiki.page:
            print(page.title.cdata)
            for text in page.revision.text:
                print(text.cdata)
        

        【讨论】:

        • 我已经使用en.wikipedia.org/wiki/Special:Export 页面导出了一些页面,它就像一个魅力。
        • 这是一个很好/简单的答案,适用于示例数据,但它不太可能适用于来自大型 wiki 的“真实”Mediawiki XML 转储,这些 wiki 的大小通常为数千兆字节(甚至 Wikipedia 的 TB)。在这种情况下,唯一真正的解决方案涉及某种基于流的 XML 解析解决方案。
        【解决方案5】:

        您正试图获取&lt;page&gt; 元素的text 属性的内容,但这只是空格。

        要获取&lt;text&gt; 元素的text,只需更改

        elif tname == 'page':
        

        elif tname == 'text':
        

        【讨论】:

          猜你喜欢
          • 2011-02-21
          • 2013-12-06
          • 1970-01-01
          • 2015-03-28
          • 2012-10-21
          • 2022-01-24
          • 2013-09-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多