帮助:Python
Python是一种简明、易学的解释型语言,运行Python脚本不需要编译,因此可以方便的部署和使用。本教程着重介绍如何在MediaWiki的场景下使用Python 3.x语言。
关于Python
自2020 年 1 月 1 日起, Python 2 的更新已经停止,因此我们在这里只讨论Python 3版本的相关内容。关于在灰机使用Python,需要明确:
- 出于安全考虑,灰机无法在线上运行Python脚本,线上的逻辑编译我们推荐使用MediaWiki内建支持的Lua进行编程。
- Python在本地使用时,可以搭配各种bot工具,比如AWB或者灰机数据更新器,但我们不推荐使用PyWikibot(太麻烦)。
Python能做什么?
Python的作用主要在于为线上准备编辑材料,比如文学翻译类维基的译名表,游戏类维基的结构化数据,甚至制作镜像wiki。概括来说,Python最擅长的功能主要包括:
- 提取、拆分结构化数据,实现包文件、文本文件(txt、hex等)、结构化数据之间(XML、JSON、CSV)的互转;
- 将Excel表格(xls,xlsx)以CSV的形式与XML、JSON、txt进行互转;
- 将数据按照你想要的结构进行重构,比如多语言字段的merge、大体积JSON文件(超过2M)的切割等等;
- 快速的备份灰机或其他MediaWiki网站的文字和图片内容(请注意节操!);
- 将预处理的内容直接更新到灰机(与灰机数据更新器、AWB存在一定程度上的重合,请自行判断用哪个方法)。
学习Python
Python的文档和教程可以前往菜鸟教程自行阅读。
- 注意,请勿死记硬背,尽量在具体项目中实践摸索。
安装Python
安装和部署Python环境,主要是要安装Python本体,和JB家的Python编译工具,下面是地址
配置解释器
- File——Other Settings——Setting for New Project ——
- Project Interpreter ——下拉选择编译器,通过右侧的“+”安装需要的库(lib)——
- 运行脚本——Edit Configuration——选择之前配置完毕的interpreter——运行
常用库
库 | 用途 | 类型 | 文档 |
---|---|---|---|
beautifulsoup4 | 爬虫和网页内容处理 | 外部库,需要安装 | 中文 |
mwclient | MW的API通信 | 外部库,需要安装 | 英文 |
requests | 网络请求 | 外部库,需要安装 | 中文 |
urllib3 | 网络请求 | 外部库,需要安装 | 英文 |
json | JSON编码 | 内部库,直接导入 | 英文 |
csv | CSV编码 | 内部库,直接导入 | 英文 |
re | 正则表达式 | 内部库,直接导入 | 英文 |
os | 本地文件操作 | 内部库,直接导入 | 英文 |
time | 时间 | 内部库,直接导入 | 英文 |
slpp | lua编码 | 外部库,需要安装 | 英文 |
xmltodict | XML编码 | 外部库,需要安装 | 英文 |
方法一,非直接交互
顾名思义,您的Python脚本无需直接和灰机服务器进行通信,而是通过灰机数据更新器将您的本地资料上传到灰机的服务器,典型使用场景:
- 本地解包,Python将包文件编译为JSON文件,通过灰机数据更新器同步到灰机wiki的Data命名空间下,存入MongoDB,然后使用Lua在线上进行查询。
- 本地使用Python爬取目标网站的图片或者特定信息(请确认您的爬虫行为符合网络礼仪且合法!),在本地预处理成新增信息,通过灰机数据更新器更新到页面模板中。
方法二:直接交互
这里主要用到一个Python的库,叫做mwclient
连接
from mwclient import Site
site = Site('test.huijiwiki.com', scheme="http")
灰机建议使用http发送请求,否则有可能被ban。
声明自己的ua
{tool_name}/{tool_version} ({contact})
.非强制,但推荐
ua = 'MyCoolTool/0.2 ([email protected])' site = Site('test.huijiwiki.com', clients_useragent=ua)
登录
site.login('my_username', 'my_password')
操作页面
拿到特定页面的内容,代码如下
from mwclient import Site site = Site('www.huijiwiki.com, scheme="http"') page = site.pages['help:Python'] text = page.text()
编辑页面
通过page.exists
可以对指定页面是否存在进行判断
page.exists
在指定的字符串内装载完毕更新内容后,使用
page.save(text, 'Edit summary')
来进行更新,页面存在进行编辑,不存在则进行创建。
获取分类
Site.categories()
获取站点的分类信息,同时可以使用 members()
列出分类中的内容。
Category object本身就是一个iterator,用法如下
category = site.categories['Python'] for page in category: print(page.name)
处理文件
获取指定文件的信息
file = site.images['Example.jpg']
print(file.imageinfo) {'comment': 'Reverted to version as of 17:58, 12 March 2010', 'descriptionshorturl': 'https://commons.wikimedia.org/w/index.php?curid=6428847', 'descriptionurl': 'https://commons.wikimedia.org/wiki/File:Example.jpg', 'height': 178, 'metadata': [{'name': 'MEDIAWIKI_EXIF_VERSION', 'value': 1}], 'sha1': 'd01b79a6781c72ac9bfff93e5e2cfbeef4efc840', 'size': 9022, 'timestamp': '2010-03-14T17:20:20Z', 'url': 'https://upload.wikimedia.org/wikipedia/commons/a/a9/Example.jpg', 'user': 'SomeUser', 'width': 172}
获取使用目标图片的条目
for page in image.imageusage(): print('Page:', page.name, '; namespace:', page.namespace)
注意:通过共享的图片不被视为物理存在
下载文件
Image.download()
例子:
file = site.images['Example.jpg'] with open('Example.jpg', 'wb') as fd: ... image.download(fd)
上传文件
site.upload(open('file.jpg'), 'destination.jpg', 'Image description')
页面(Page Object)
通过Page
、Category
、 Image
进行操作,一般用Site.pages
作为generator生成迭代器遍历。
page = site.Pages['Template:Stub'] # a Page object image = site.Pages['Image:Wiki.png'] # an Image object image = site.Images['Wiki.png'] # the same Image object cat = site.Pages['Category:Python'] # a Category object cat = site.Images['Python'] # the same Category object
手册索引
搜索替换的代码实例
import re from mwclient import Site site = Site('asdasd.huijiwiki.com, scheme="http"') site.login('SerGawen', '123123123123') category = site.categories['categoryxxx'] def find_and_replace(): for page in category: change = 0 # 获取页面内容(str) text = page.text() # find 1 使用普通的文本替换 obj = re.search('regex', text) if obj: new = '123123123123' # use replace text = text.replace('{{ShowCardText}}', new) change += 1 # find 2 使用正则表达式 obj2 = re.search('regex', text) if obj2: new = '13123123' # 使用正则表达式capture并返回\1 text = re.sub(r'(\=\=\=)', '\1', text) # 使用程序作为re.sub的repl text = re.sub('("[a-zA-Z]+":\s[\w\[,\s]+)', processValue, text) change += 1 if change > 0: page.save(text, summary='fix', minor=False, bot=True, section=None) print("changed : %s" % page) # 如果使用程序作为re.sub的repl部分: def processValue(m): res = '' n = str(m.group(1)).split(':') # 切片 for slice in n: # 没有引号的 if re.search('"',slice) is None: # 有英文字符串的 match = re.findall('[\w\._]+',slice) if match is not None: # 每个正确的匹配 if match != 'true' and match != 'false': slice = re.sub('([\w\._]+)', r'"\1"', slice) res = res + slice + ':' res = res[0:len(res)-1] return res find_and_replace()
从MediaWiki站点备份图片代码实例
import os import requests from mwclient import Site root_path = 'H:\\download' # file path # 这里的实例为Fandom,注意,Fandom没有采用默认的api路径,需要手动指定一个path。 def getFandomSite(prefix): site = Site(prefix + '.fandom.com', path='/') # 获取所有图片文件 allImages = site.allimages() for img in allImages: file = img.name url = img.imageinfo['url'] r = requests.get(url, stream=True) name = file.replace("File:", '') # 防雷补丁 name = name.replace("/", '%2F') name = name.replace(":", '%3A') name = name.replace("*", '%2A') name = name.replace("?", '%3F') name = name.replace('"', '%22') path = root_path + '\\' + prefix if not os.path.exists(path): os.mkdir(path) path = path + '\\' + name # 保存文件 if not os.path.exists(path): try: with open(path, 'wb') as fd: fd.write(r.content) print(path) except Exception: print("erro: %s" % path) pass # 指定站点为 avatar.fandom.com getFandomSite('avatar')
import os import requests from mwclient import Site root_path = 'H:\\download' # file path def getHuijiSiteFlags(prefix): site = Site('shareduploads.huijiwiki.com', scheme='http') allImages = site.categories['国旗和区旗'] for img in allImages: file = img.name if 'url' in img.imageinfo: url = img.imageinfo['url'] if 'url' in img.imageinfo: r = requests.get(url, stream=True) name = file.replace("文件:", '') # 防雷 name = name.replace("/", '%2F') name = name.replace(":", '%3A') name = name.replace("*", '%2A') name = name.replace("?", '%3F') name = name.replace('"', '%22') path = root_path + '\\' + prefix if not os.path.exists(path): os.mkdir(path) path = path + '\\' + name if not os.path.exists(path): try: with open(path, 'wb') as fd: fd.write(r.content) print(path) except Exception: pass getHuijiSiteFlags('flags')