Skip to main content

MediaWiki 的 wikitext 标记的简单解析工具。

项目描述

https://github.com/5j9/wikitextparser/actions/workflows/tests.yml/badge.svg https://codecov.io/github/5j9/wikitextparser/coverage.svg?branch=master https://readthedocs.org/projects/wikitextparser/badge/?version=latest

维基文本解析器

用于MediaWiki的简单易用的 WikiText 解析库。

目的是允许用户轻松提取和/或操作维基文本中的模板、模板参数、解析器函数、表格、外部链接、维基链接、列表等。

<nav class="contents" id="table-of-contents">

目录

</nav>

安装

  • 需要 Python 3.6+

  • 点安装 wikitextparser

用法

>>> import wikitextparser as wtp

WikiTextParser 可以检测您的 wikitext 中的部分、解析器函数、模板、wiki 链接、外部链接、参数、表格、wiki 列表和评论。以下部分是其中一些功能的快速概述。

您可能还想查看测试模块以获取更多示例和可能的陷阱(预期失败)。

模板

>>> parsed = wtp.parse("{{text|value1{{text|value2}}}}")
>>> parsed.templates
[Template('{{text|value1{{text|value2}}}}'), Template('{{text|value2}}')]
>>> parsed.templates[0].arguments
[Argument("|value1{{text|value2}}")]
>>> parsed.templates[0].arguments[0].value = 'value3'
>>> print(parsed)
{{text|value3}}

pformat方法为模板返回一个漂亮打印的格式化字符串:

>>> parsed = wtp.parse('{{t1 |b=b|c=c| d={{t2|e=e|f=f}} }}')
>>> t1, t2 = parsed.templates
>>> print(t2.pformat())
{{t2
    | e = e
    | f = f
}}
>>> print(t1.pformat())
{{t1
    | b = b
    | c = c
    | d = {{t2
        | e = e
        | f = f
    }}
}}

Template.rm_dup_args_safeTemplate.rm_first_of_dup_args方法可用于在模板调用中使用重复参数清理页面:

>>> t = wtp.Template('{{t|a=a|a=b|a=a}}')
>>> t.rm_dup_args_safe()
>>> t
Template('{{t|a=b|a=a}}')
>>> t = wtp.Template('{{t|a=a|a=b|a=a}}')
>>> t.rm_first_of_dup_args()
>>> t
Template('{{t|a=a}}')

模板参数:

>>> param = wtp.parse('{{{a|b}}}').parameters[0]
>>> param.name
'a'
>>> param.default
'b'
>>> param.default = 'c'
>>> param
Parameter('{{{a|c}}}')
>>> param.append_default('d')
>>> param
Parameter('{{{a|{{{d|c}}}}}}')

部分

>>> parsed = wtp.parse("""
... == h2 ==
... t2
... === h3 ===
... t3
... === h3 ===
... t3
... == h22 ==
... t22
... {{text|value3}}
... [[Z|X]]
... """)
>>> parsed.sections
[Section('\n'),
 Section('== h2 ==\nt2\n=== h3 ===\nt3\n=== h3 ===\nt3\n'),
 Section('=== h3 ===\nt3\n'),
 Section('=== h3 ===\nt3\n'),
 Section('== h22 ==\nt22\n{{text|value3}}\n[[Z|X]]\n')]
>>> parsed.sections[1].title = 'newtitle'
>>> print(parsed)

==newtitle==
t2
=== h3 ===
t3
=== h3 ===
t3
== h22 ==
t22
{{text|value3}}
[[Z|X]]
>>> del parsed.sections[1].title
>>>> print(parsed)

t2
=== h3 ===
t3
=== h3 ===
t3
== h22 ==
t22
{{text|value3}}
[[Z|X]]

提取表格的单元格值:

>>> p = wtp.parse("""{|
... |  Orange    ||   Apple   ||   more
... |-
... |   Bread    ||   Pie     ||   more
... |-
... |   Butter   || Ice cream ||  and more
... |}""")
>>> p.tables[0].data()
[['Orange', 'Apple', 'more'],
 ['Bread', 'Pie', 'more'],
 ['Butter', 'Ice cream', 'and more']]

默认情况下,值根据colspanrowspan属性排列:

>>> t = wtp.Table("""{| class="wikitable sortable"
... |-
... ! a !! b !! c
... |-
... !colspan = "2" | d || e
... |-
... |}""")
>>> t.data()
[['a', 'b', 'c'], ['d', 'd', 'e']]
>>> t.data(span=False)
[['a', 'b', 'c'], ['d', 'e']]

调用 Table 的cells方法将表格单元格作为Cell对象返回。单元格对象提供了单独获取或设置每个单元格的属性或值的方法:

>>> cell = t.cells(row=1, column=1)
>>> cell.attrs
{'colspan': '2'}
>>> cell.set('colspan', '3')
>>> print(t)
{| class="wikitable sortable"
|-
! a !! b !! c
|-
!colspan = "3" | d || e
|-
|}

可以通过get_attrset_attrhas_attrdel_attr方法访问 Table、Cell 和 Tag 对象的 HTML 属性 。

列表

get_lists方法提供对 wikitext 中列表的访问。

>>> parsed = wtp.parse(
...     'text\n'
...     '* list item a\n'
...     '* list item b\n'
...     '** sub-list of b\n'
...     '* list item c\n'
...     '** sub-list of b\n'
...     'text'
... )
>>> wikilist = parsed.get_lists()[0]
>>> wikilist.items
[' list item a', ' list item b', ' list item c']

sublists方法可用于获取当前列表的所有子列表或仅获取特定项目的子列表:

>>> wikilist.sublists()
[WikiList('** sub-list of b\n'), WikiList('** sub-list of b\n')]
>>> wikilist.sublists(1)[0].items
[' sub-list of b']

它还有一个可选的模式参数,其工作方式类似于列表,除了当前列表模式将作为前缀自动添加到其中:

>>> wikilist = wtp.WikiList('#a\n#b\n##ba\n#*bb\n#:bc\n#c', '\#')
>>> wikilist.sublists()
[WikiList('##ba\n'), WikiList('#*bb\n'), WikiList('#:bc\n')]
>>> wikilist.sublists(pattern='\*')
[WikiList('#*bb\n')]

使用 convert 方法将一种类型的列表转换为另一种类型。指定所需列表的起始模式有助于查找它们并提高性能:

>>> wl = wtp.WikiList(
...     ':*A1\n:*#B1\n:*#B2\n:*:continuing A1\n:*A2',
...     pattern=':\*'
... )
>>> print(wl)
:*A1
:*#B1
:*#B2
:*:continuing A1
:*A2
>>> wl.convert('#')
>>> print(wl)
#A1
##B1
##B2
#:continuing A1
#A2

标签

访问 HTML 标签:

>>> p = wtp.parse('text<ref name="c">citation</ref>\n<references/>')
>>> ref, references = p.get_tags()
>>> ref.name = 'X'
>>> ref
Tag('<X name="c">citation</X>')
>>> references
Tag('<references/>')

WikiTextParser 能够处理 HTML 和扩展标签的常见用法。然而,它不是一个成熟的 HTML 解析器,可能会在边缘情况或格式错误的 HTML 输入时失败。如果您遇到错误,请在 github 上打开一个问题。

各种各样的

parentparents方法可用于分别访问节点的父节点或祖先节点:

>>> template_d = parse("{{a|{{b|{{c|{{d}}}}}}}}").templates[3]
>>> template_d.ancestors()
[Template('{{c|{{d}}}}'),
 Template('{{b|{{c|{{d}}}}}}'),
 Template('{{a|{{b|{{c|{{d}}}}}}}}')]
>>> template_d.parent()
Template('{{c|{{d}}}}')
>>> _.parent()
Template('{{b|{{c|{{d}}}}}}')
>>> _.parent()
Template('{{a|{{b|{{c|{{d}}}}}}}}')
>>> _.parent()  # Returns None

如果查找特定类型的祖先,请使用可选的type_参数:

>>> parsed = parse('{{a|{{#if:{{b{{c<!---->}}}}}}}}')
>>> comment = parsed.comments[0]
>>> comment.ancestors(type_='ParserFunction')
[ParserFunction('{{#if:{{b{{c<!---->}}}}}}')]

要从其父对象中删除/移除任何对象,请使用del object[:]del object.string

remove_markup函数或plain_text方法可用于删除 wiki 标记

>>> from wikitextparser import remove_markup, parse
>>> s = "'''a'''<!--comment--> [[b|c]] [[d]]"
>>> remove_markup(s)
'a c d'
>>> parse(s).plain_text()
'a c d'

与 mwparserfromhell 相比

mwparserfromhell是一个成熟且广泛使用的库,其用途与wikitextparser几乎相同。导致我创建wikitextparser的主要原因是mwparserfromhell在某些我需要它的情况下无法解析 wikitext。请参阅 mwparserfromhell 的问题404288和其他相关问题。在许多情况下,wikitextparser可能能够为您提供更可接受的结果。

另请注意,wikitextparser仍在使用 0.xy 版本,这意味着API 不稳定,可能会在未来的版本中发生变化。

mwparserfromhell中的分词器是用 C 编写的。wikitextparser 中的分词主要是使用C 语言中的正则表达式库完成的。我没有严格比较这两个库的性能,即执行时间和内存使用情况。以我有限的经验,wikitextparser在实际情况下具有不错的性能,应该能够竞争,在某些情况下甚至可能几乎没有性能优势。

如果您有机会在性能或功能方面比较这些库,请通过在 github 上打开问题分享您的经验。

wikitextparser的一些独特功能是:提供对每个表格的单个单元格的访问、漂亮的打印模板、带有基本方法的 WikiList 类来处理列表,以及一些其他功能。

已知问题和限制

  • 离线解析器不知道模板/参数的内容。例如,离线解析器无法知道标记[[{{z|a}}]]是否应该被视为 wikilink,这取决于{{z}}模板的内部工作。在这些情况下, wikitextparser 会尝试使用最佳猜测。[[{{z|a}}]]被视为 wikilink(为什么其他人会在 wikilink 标记中调用模板,即使它不是 wikilink,通常也不会造成任何伤害)。

  • 本地化的命名空间名称是未知的,因此例如[[File:...]]链接被视为普通的维基链接。mwparserfromhell有类似的问题,请参阅#87#136。作为一种解决方法,Pywikibot可用于确定命名空间。

  • Linktrails依赖于语言,不受支持。mwparserfromhell 也不支持。然而,鉴于轨迹模式并知道wikilink.span[1]是 wikilink 的结束位置,计算 WikiLink 的链接轨迹是可能的。

  • 与外部链接相邻的模板永远不会被视为链接的一部分。实际上,这取决于模板的内容。示例:parse('http://example.com{{dead link}}').external_links[0].url == 'http://example.com'

  • 有效扩展标签列表取决于 wiki 上安装的扩展。tags方法目前只支持英文维基百科上的那些。将来可能会添加一个配置选项来解决此问题。

  • wikitextparser目前不提供类似 ast.walk的方法来产生所有后代节点。

  • 解析器函数魔术词不被评估。

学分

项目详情