API:编辑
本页是MediaWiki Action API帮助文档的一部份。 |
MediaWiki版本: | ≥ 1.13 |
使用POST 请求编辑某个页面。
API帮助文档
示例
此示例中的示例代码使用Python。 有关示例请见API:Edit/Editing with Ajax ,响应请参阅Ajax 。
POST请求
编辑,以及任何POST请求实际上都是一个多步骤的过程。
- 1. 使用API:登录 中描述的方法之一登录。 请注意,虽然此操作需要将其正确地归为编辑者的贡献,但许多Wiki确实允许用户无需注册或登录帐户即可进行编辑。
- 2. 获取CSRF令牌 :
- 3. 发送带有CSRF令牌的POST请求以在页面上执行操作:
下方的“回应”段落显示了最终的POST请求,以在页面上执行操作。 请参阅API:登录 和API:令牌 的页面,以获取对先前步骤的中间JSON响应。
另请注意,此页面上查询中的令牌(tokens)是示例值。 实际的令牌对于每个登录会话和跨站请求都是唯一的。 示例中包括它们只是为了演示如何正确格式化查询。
回应
{
"edit": {
"result": "Success",
"pageid": 94542,
"title": "Wikipedia:Sandbox",
"contentmodel": "wikitext",
"oldrevid": 371705,
"newrevid": 371707,
"newtimestamp": "2018-12-18T16:59:42Z"
}
}
示例代码
Python
#!/usr/bin/python3
"""
edit.py
MediaWiki API Demos
Demo of `Edit` module: POST request to edit a page
MIT license
"""
import requests
S = requests.Session()
URL = "https://test.wikipedia.org/w/api.php"
# Step 1: GET request to fetch login token
PARAMS_0 = {
"action": "query",
"meta": "tokens",
"type": "login",
"format": "json"
}
R = S.get(url=URL, params=PARAMS_0)
DATA = R.json()
LOGIN_TOKEN = DATA['query']['tokens']['logintoken']
# Step 2: POST request to log in. Use of main account for login is not
# supported. Obtain credentials via Special:BotPasswords
# (https://www.mediawiki.org/wiki/Special:BotPasswords) for lgname & lgpassword
PARAMS_1 = {
"action": "login",
"lgname": "bot_user_name",
"lgpassword": "bot_password",
"lgtoken": LOGIN_TOKEN,
"format": "json"
}
R = S.post(URL, data=PARAMS_1)
# Step 3: GET request to fetch CSRF token
PARAMS_2 = {
"action": "query",
"meta": "tokens",
"format": "json"
}
R = S.get(url=URL, params=PARAMS_2)
DATA = R.json()
CSRF_TOKEN = DATA['query']['tokens']['csrftoken']
# Step 4: POST request to edit a page
PARAMS_3 = {
"action": "edit",
"title": "Project:Sandbox",
"token": CSRF_TOKEN,
"format": "json",
"appendtext": "Hello"
}
R = S.post(URL, data=PARAMS_3)
DATA = R.json()
print(DATA)
PHP
<?php
/*
edit.php
MediaWiki API Demos
Demo of `Edit` module: POST request to edit a page
MIT license
*/
$endPoint = "https://test.wikipedia.org/w/api.php";
$login_Token = getLoginToken(); // Step 1
loginRequest( $login_Token ); // Step 2
$csrf_Token = getCSRFToken(); // Step 3
editRequest($csrf_Token); // Step 4
// Step 1: GET request to fetch login token
function getLoginToken() {
global $endPoint;
$params1 = [
"action" => "query",
"meta" => "tokens",
"type" => "login",
"format" => "json"
];
$url = $endPoint . "?" . http_build_query( $params1 );
$ch = curl_init( $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_COOKIEJAR, "cookie.txt" );
curl_setopt( $ch, CURLOPT_COOKIEFILE, "cookie.txt" );
$output = curl_exec( $ch );
curl_close( $ch );
$result = json_decode( $output, true );
return $result["query"]["tokens"]["logintoken"];
}
// Step 2: POST request to log in. Use of main account for login is not
// supported. Obtain credentials via Special:BotPasswords
// (https://www.mediawiki.org/wiki/Special:BotPasswords) for lgname & lgpassword
function loginRequest( $logintoken ) {
global $endPoint;
$params2 = [
"action" => "login",
"lgname" => "bot_user_name",
"lgpassword" => "bot_password",
"lgtoken" => $logintoken,
"format" => "json"
];
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $endPoint );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $params2 ) );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_COOKIEJAR, "cookie.txt" );
curl_setopt( $ch, CURLOPT_COOKIEFILE, "cookie.txt" );
$output = curl_exec( $ch );
curl_close( $ch );
}
// Step 3: GET request to fetch CSRF token
function getCSRFToken() {
global $endPoint;
$params3 = [
"action" => "query",
"meta" => "tokens",
"format" => "json"
];
$url = $endPoint . "?" . http_build_query( $params3 );
$ch = curl_init( $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_COOKIEJAR, "cookie.txt" );
curl_setopt( $ch, CURLOPT_COOKIEFILE, "cookie.txt" );
$output = curl_exec( $ch );
curl_close( $ch );
$result = json_decode( $output, true );
return $result["query"]["tokens"]["csrftoken"];
}
// Step 4: POST request to edit a page
function editRequest( $csrftoken ) {
global $endPoint;
$params4 = [
"action" => "edit",
"title" => "Project:Sandbox",
"appendtext" => "Hello",
"token" => $csrftoken,
"format" => "json"
];
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $endPoint );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $params4 ) );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_COOKIEJAR, "cookie.txt" );
curl_setopt( $ch, CURLOPT_COOKIEFILE, "cookie.txt" );
$output = curl_exec( $ch );
curl_close( $ch );
echo ( $output );
}
JavaScript
/*
edit.js
MediaWiki API Demos
Demo of `Edit` module: POST request to edit a page
MIT license
*/
var request = require('request').defaults({jar: true}),
url = "https://test.wikipedia.org/w/api.php";
// Step 1: GET request to fetch login token
function getLoginToken() {
var params_0 = {
action: "query",
meta: "tokens",
type: "login",
format: "json"
};
request.get({ url: url, qs: params_0 }, function (error, res, body) {
if (error) {
return;
}
var data = JSON.parse(body);
loginRequest(data.query.tokens.logintoken);
});
}
// Step 2: POST request to log in.
// Use of main account for login is not
// supported. Obtain credentials via Special:BotPasswords
// (https://www.mediawiki.org/wiki/Special:BotPasswords) for lgname & lgpassword
function loginRequest(login_token) {
var params_1 = {
action: "login",
lgname: "bot_username",
lgpassword: "bot_password",
lgtoken: login_token,
format: "json"
};
request.post({ url: url, form: params_1 }, function (error, res, body) {
if (error) {
return;
}
getCsrfToken();
});
}
// Step 3: GET request to fetch CSRF token
function getCsrfToken() {
var params_2 = {
action: "query",
meta: "tokens",
format: "json"
};
request.get({ url: url, qs: params_2 }, function(error, res, body) {
if (error) {
return;
}
var data = JSON.parse(body);
editRequest(data.query.tokens.csrftoken);
});
}
// Step 4: POST request to edit a page
function editRequest(csrf_token) {
var params_3 = {
action: "edit",
title: "Project:Sandbox",
appendtext: "test edit",
token: csrf_token,
format: "json"
};
request.post({ url: url, form: params_3 }, function (error, res, body) {
if (error) {
return;
}
console.log(body);
});
}
// Start From Step 1
getLoginToken();
MediaWiki JS
/*
edit.js
MediaWiki API Demos
Demo of `Edit` module: POST request to edit a page
MIT License
*/
var params = {
action: 'edit',
title: 'Project:Sandbox',
appendtext: 'Hello',
format: 'json'
},
api = new mw.Api();
api.postWithToken( 'csrf', params ).done( function ( data ) {
console.log( data );
} );
使用示例
编辑冲突
“Python示例”是一个对于注册用户编辑请求的简单实现。 在实际情况下,应注意防止编辑冲突。 当两个或多个用户试图同时编辑同一页面时,可能会发生这种情况。
当我们请求CSRF令牌时,可以通过检索最后编辑版本 的时间戳来避免冲突。
在第3步的CSRF令牌请求中加入prop=info|revisions
可以获取最新版本的时间戳。
当我们发出编辑请求时,此时间戳将用作basetimestamp
。
此外还需要开始编辑的准确时间。
同样可以通过在CSRF请求中添加curtimestamp
来检索此内容。
该值将作为starttimestamp
。
最后,在实际的编辑请求中,将basetimestamp
和starttimestamp
参数设定为类似如下内容:
大编辑
包含了大量的文本内容(超过8000个字符)的POST请求应该在请求头中加入Content-Type: multipart/form-data
。
由于multipart/form-data
无需对空格和标点进行HTML字符转义(例如,百分比编码),传输的数据量将会比使用百分比编码的相同内容数据更小。
但是,multipart/form-data
仍然会增加一些开销——每个参数大约160个字节。
对于不需要添加许多转义符的短消息,此开销量可能是低效的,因此百分比编码是这一情况的首选。[1]
请注意对于上文的Python示例代码,该请求默认使用百分比编码。
请参见MDN Web 文档来获取有关内容类型(content-type)和POST请求的更多技术讨论。
请参见Python Requests文档来获取如何使用与Python示例代码类似的方法来传递multipart/form-data
。
验证码
如果您的目标wiki使用验证码 ,您的请求可能会返回一个错误值,该值包含了一个id编号和简单的测验,例如一个问题、一道数学题或是一张图片的URL。
为了完成您的编辑,您必须完成这一测验,然后将id和正确的答案附在原始的请求字符串后并再次发送请求,例如: captchaid=sampleId&captchaword=answer
其他验证码系统和插件可能会使用类似的不同参数。 通常情况下,将id和测试题的字段名称用作第二个请求中的参数。
可能的错误
代码 | 信息 |
---|---|
notitle | title参数必须被设置。 |
missingparam | 需要text、appendtext和undo中的至少一个参数。 |
notoken | token参数必须被设置。 |
invalidsection | section参数必须为有效的章节ID或new。 |
protectedpage | 此页面已受到保护,以防止编辑或其他操作。 |
cantcreate | 您没有权限创建新页面。 |
cantcreate-anon | 匿名用户无法创建新页面 |
articleexists | 您尝试创建的页面已经被创建。 |
noimageredirect-anon | 匿名用户不能创建图片重定向。 |
noimageredirect | 您没有权限创建图片重定向。 |
spamdetected | 您的编辑被拒绝,因为它包含垃圾部分:Wikitext 。
|
abusefilter-warning | 此操作已被自动识别为有害。 |
abusefilter-disallowed | 此操作已被自动识别为有害,并已不被允许。 |
contenttoobig | 您提供的内容超过了bytes千字节的页面大小限制。 Where bytes is the value of $wgMaxArticleSize . |
noedit-anon | 匿名用户不能编辑页面。 |
noedit | 您没有权限编辑页面。 |
pagedeleted | 在您取得页面时间戳以来,页面已被删除。 |
emptypage | 不允许创建新的、空的页面。 |
emptynewsection | 无法创建空的新章节。 |
editconflict | 编辑冲突。 |
revwrongpage | rrevid不是pagename的修订版本。 如果 undo 或undoafter 的revid (版本id)有误将会抛出此错误
|
undofailure | 因存在冲突的中间编辑,本编辑不能撤销。 |
missingtitle | 您指定的页面不存在。 (参见上文 nocreate 参数)
|
mustbeposted | edit模块需要POST请求。 |
readapidenied | 您需要读取权限以使用此模块。 |
writeapidenied | 您不被允许通过API编辑此wiki。 |
noapiwrite | 通过API编辑此wiki已禁用。 |
badtoken | 无效的CSRF令牌。 |
missingparam | title, pageid参数必须被设置。 |
invalidparammix | 参数title, pageid不能一起使用。 |
invalidtitle | 错误标题“title”。 |
invalid-content-data | 无效的内容数据 尝试编辑包含不合规数据的JSON页面或尝试编辑MassMessageListContent页面时发生 |
nosuchpageid | 没有ID为pageid的页面。 |
pagecannotexist | 命名空间不允许实际页面。 |
nosuchrevid | 没有ID为undo的修订版本。 |
nosuchrevid | 没有ID为undoafter的修订版本。 |
badmd5 | 提供的MD5哈希不正确。 |
hookaborted | 您尝试的修改被扩展程序中止。 |
parseerror | 内容序列化失败:parseerror |
summaryrequired | ⧼apierror-summaryrequired⧽ |
blocked | 您已被封禁,不能编辑。 |
ratelimited | 您已超过您的速率限制。请等待一段时间再试。 |
unknownerror | 未知错误:“retval”。 |
nosuchsection | 没有章节$1。 |
sectionsnotsupported | 内容模型$1不支持章节。 |
editnotsupported | 不支持使用基于文字的编辑API编辑此类型页面。 |
appendnotsupported | 不能使用内容模型$1附加在页面上。 |
redirect-appendonly | 您试图使用重定向跟随模式编辑,而这必须与section=new、prependtext或appendtext共同使用。 |
edit-invalidredirect | 跟随重定向时无法编辑$1,因为目标$2无效。 |
badformat | 由$3使用的内容模型$2尚不支持请求的内容格式$1。 |
customcssprotected | 您没有权限编辑此CSS页面,因为此页面包含另一位用户的个人设置。 |
customjsprotected | 您没有权限编辑此JavaScript页面,因为此页面包含另一位用户的个人设置。 |
taggingnotallowed | 您无权应用标签 |
badtags | 标签“Tag”不允许手动应用。 以下标签不允许手动应用:Tag1、 Tag2 |
tpt-target-page | 本页面无法手动更新。本页面是$1页面的翻译版,可以使用[$2 翻译工具]来更新该翻译。 如果使用了Extension:翻译 ,那么不允许编辑被翻译的子页面。 |
参数历史
- v1.35: 启用
baserevid
- v1.25: 启用
tags
- v1.21: 启用
contentformat
,contentmodel
- v1.20: 启用
pageid
- v1.19: 启用
sectiontitle
- v1.18: 弃用
captchaid
,captchaword
- v1.17: 启用
redirect
- v1.16: 弃用
watch
,unwatch
- v1.16: 启用
watchlist
- v1.15: 启用
undo
,undoafter
- v1.14: 启用
starttimestamp
更多注释
- API并不严格需要登录,但登录操作可以正确地标记作者的贡献。 未登录用户的成功编辑将以IP地址作为贡献者。
- 未登录的机器人可能会面临编辑和其他写入请求的限制;有关更多详细信息,请参见创建机器人#登录 。
- 未登录的用户将始终获得空的CSRF令牌
+\
。 - 请求令牌的过程在各个版本中已多次更改。 参见API:令牌 以获取更多信息。
- ResourceLoader 提供了一种在Wiki页面中运行代码时获取编辑令牌的方法。
- 在单个登录会话期间,您可以对同一Wiki中的所有编辑操作使用相同的CSRF令牌。
- 优良作法是在查询字符串的末尾,或至少在text参数之后传递请求中的所有令牌。 这样,如果连接中断,令牌将不会被传递,因此编辑将失败。 如果您使用了mw.Api 来发送请求,那么这一操作会自动进行。
- 尽管从1.18版本开始,
captchaid
和captchaword
已经在技术上从API:Edit中移除,但Extension:ConfirmEdit 扩展了API:Edit以便与验证码一起使用。 因此,如果安装了ConfirmEdit插件,这些参数仍然可用。 在1.18及以后版本的MediaWiki中附带了ConfirmEdit。
參見
- Help:编辑 - 包含对编辑页面有用的链接
- Manual:Bot passwords - 描述了通过脚本或应用程序而不是GUI访问Wiki时如何使用简化界面登录。
- Manual:Creating a bot - 更多有关使用机器人自动编辑页面的详细信息。
- ResourceLoader - 提供在MediaWiki页面中运行JavaScript时访问编辑令牌的方法。
- API:令牌 - 包含了有关使用令牌登录或发出POST请求的更多详细信息。
- API:令牌(操作) - 已弃用的API,与API:令牌 不同,用于在早期版本的MediaWiki中请求令牌。
- API:Compare - 允许您查看页面的两个修订版本之间的差异。
- API:Managetags - 修改一个页面的标签
- API:回退 - 回退一系列编辑。
- API:Filerevert - 将文件回退到其较早的状态。
- API:修订版本删除 - 删除并恢复页面的修订版本。