我想在Python中获得这个Wikimedia Scribunto模块的返回值。它的源代码大致如下:
local Languages = {}
Languages = {
["aa"] = {
name = "afarština",
dir = "ltr",
name_attr_gen_pl = "afarských"
},
-- More languages...
["zza"] = {
name = "zazaki",
dir = "ltr"
}
}
return Languages
在wiktext库中,已经有Python代码来完成类似的任务:
def expand_template(sub_domain: str, text: str) -> str:
import requests
# https://www.mediawiki.org/wiki/API:Expandtemplates
params = {
"action": "expandtemplates",
"format": "json",
"text": text,
"prop": "wikitext",
"formatversion": "2",
}
r = requests.get(f"https://{sub_domain}.wiktionary.org/w/api.php",
params=params)
data = r.json()
return data["expandtemplates"]["wikitext"]
这适用于像法语这样的语言,因为在这些语言中,Scribunto模块有一个定义良好的返回值的函数,如下所示:
Scribunto模块:
p = {}
function p.affiche_langues_python(frame)
-- returns the needed stuff here
end
相关的Python函数:
def get_fr_languages():
# https://fr.wiktionary.org/wiki/Module:langues/analyse
json_text = expand_template(
"fr", "{{#invoke:langues/analyse|affiche_langues_python}}"
)
json_text = json_text[json_text.index("{") : json_text.index("}") + 1]
json_text = json_text.replace(",rn}", "}") # remove tailing comma
data = json.loads(json_text)
lang_data = {}
for lang_code, lang_name in data.items():
lang_data[lang_code] = [lang_name[0].upper() + lang_name[1:]]
save_json_file(lang_data, "fr")
但是在本例中,没有可调用的函数。所以如果我们输入:
def get_cs_languages():
# https://cs.wiktionary.org/wiki/Modul:Languages
json_text = expand_template(
"cs", "{{#invoke:Languages}}"
)
print(json_text)
得到<strong class="error"><span class="scribunto-error" id="mw-scribunto-error-0">Chyba skriptu: Musíte uvést funkci, která se má zavolat.</span></strong> usage: get_languages.py [-h] sub_domain lang_code get_languages.py: error: the following arguments are required: sub_domain, lang_code
。你必须指定一个你想调用的函数。但是,当您像在法语示例中那样输入函数名作为参数时,它会报错该函数不存在。
解决这个问题的方法是什么?
最简单和最通用的方法是获取模块的返回值作为JSON并在Python中解析它。
创建另一个模块,该模块导出一个函数dump_as_json
,该函数将第一个模块的名称作为frame
参数并返回第一个模块作为JSON。在Python中,使用expandtemplates
API展开{{#invoke:json module|dump_as_json|Module:module to dump}}
,并使用json.loads(data["expandtemplates"]["wikitext"])
将模块调用的返回值解析为JSON。
Module:json module
文本(随你怎么称呼):
return {
dump_as_json = function(frame)
local module_name = frame.args[1]
local json_encode = mw.text.jsonEncode
-- json_encode = require "Module:JSON".toJSON
return json_encode(require(module_name))
end
}
Withpywikibot
:
from pywikibot import Site
site = Site(code="cs", fam="wiktionary")
languages = json.loads(site.expand_text("{{#invoke:json module|dump_as_json|Module:module to dump}}")
如果你得到错误Lua error: Cannot pass circular reference to PHP
,这意味着Module:module to dump
中的至少一个表被另一个表引用了不止一次,就像模块是
local t = {}
return { t, t }
要处理这些表,您必须获得一个纯lua JSON编码器函数来替换mw.text.jsonEncode
,就像英语维基词典上Module:JSON中的toJSON
函数一样。
关于此方法的一个警告与您试图获得的模块无关:JSON中的字符串值只有在它们从Module:module to dump
返回时是nfc规范化的有效UTF-8,没有特殊的ASCII控制代码(U+0000-U+001F,不包括制表符U+0009和LF U+000A)时才准确。在wiki页面上,expandtemplates
API将用U+FFFD字符替换ASCII控制码和无效的UTF-8,并将nfc规范化其他所有内容。也就是说,将"1128e" .. mw.ustring.char(0x0301)
修改为mw.ustring.char(0xFFFD, 0xFFFD, 0x00E9)
的等价物。这在大多数情况下并不重要(比如如果表包含可读文本),但如果它确实重要,JSON-encoding模块将不得不为非nfc字符序列和ASCII控制码输出JSON转义,并找到某种方法编码无效的UTF-8。
如果,像你要转储的模块一样,Module:module to dump
是一个纯文本值表,没有引用其他模块或只引用scribunto的全局值,你也可以用Revisions API获得它的原始wikittext,然后在你的机器上用Lua解析它,然后传递给Python。我认为有一个Python扩展可以让你直接在Python中使用Lua状态。
在本地机器上运行带有依赖项的模块是不可能的,除非您在机器上设置完整的Scribunto环境,并找出一种方法来下载模块依赖项并使它们对Lua状态可用。我自己也这样做过,但对于您的用例来说,这不是必需的。