NAME
MediaWiki::Bot - a high-level bot framework for interacting with MediaWiki wikis
VERSION
version 5.007000
SYNOPSIS
use MediaWiki::Bot qw(:constants);
my $bot = MediaWiki::Bot->new({
assert => 'bot',
host => 'de.wikimedia.org',
login_data => { username => "Mike's bot account", password => "password" },
});
my $revid = $bot->get_last("User:Mike.lifeguard/sandbox", "Mike.lifeguard");
print "Reverting to $revid\n" if defined($revid);
$bot->revert('User:Mike.lifeguard', $revid, 'rvv');
DESCRIPTION
MediaWiki::Bot is a framework that can be used to write bots which interface with the MediaWiki API (http://en.wikipedia.org/w/api.php).
METHODS
Initialization
new
my $bot = MediaWiki::Bot({
host => 'en.wikipedia.org',
operator => 'Mike.lifeguard',
});
Calling MediaWiki::Bot->new() will create a new MediaWiki::Bot object. The
only parameter is a hashref with keys:
-
agentsets a custom useragent. It is recommended to useoperatorinstead, which is all we need to do the right thing for you. If you really want to do it yourself, see https://meta.wikimedia.org/wiki/User-agent_policy for guidance on what information must be included. -
assertsets a parameter for the AssertEdit extension (commonly 'bot') -
operatorallows the bot to send you a message when it fails an assert. This is also the recommended way to customize the user agent string, which is required by the Wikimedia Foundation. A warning will be emitted if you omit this. -
maxlagallows you to set the maxlag parameter (default is the recommended 5s).Please refer to the MediaWiki documentation prior to changing this from the default.
-
protocolallows you to specify 'http' or 'https' (default is 'https') -
hostsets the domain name of the wiki to connect to (e.g. 'en.wikipedia.org') -
pathsets the path to api.php (with no leading or trailing slash, e.g. 'w') -
login_datais a hashref of credentials to pass to "login" (see "login" for more information). -
debug- whether to provide debug output (default is 0).1 provides some more warnings; 2 provides further detail on internal operations.
For example:
my $bot = MediaWiki::Bot->new({
assert => 'bot',
protocol => 'https',
host => 'en.wikimedia.org',
agent => sprintf(
'PerlWikiBot/%s (https://metacpan.org/MediaWiki::Bot; User:Mike.lifeguard)',
MediaWiki::Bot->VERSION
),
login_data => { username => "Mike's bot account", password => "password" },
});
For backward compatibility, you can specify up to three parameters:
my $bot = MediaWiki::Bot->new('My custom useragent string', $assert, $operator);
This form is deprecated, will never do auto-login or autoconfiguration, and emits deprecation warnings.
For further reading:
- MediaWiki::Bot wiki
- <Installing
MediaWiki::Bot> - Creating a new bot
- Setting the wiki
- Where is api.php
set_wiki
Set what wiki to use. The parameter is a hashref with keys:
host- the domain name (e.g. en.wikipedia.org)path- the part of the path before api.php (e.g. 'w')protocolis either 'http' or 'https'.
If you don't set any parameter, it's previous value is used. If it has never been set, the default settings are 'https', 'en.wikipedia.org' and 'w'.
For example:
$bot->set_wiki({
protocol => 'https',
host => 'en.wikimedia.org',
path => 'wikipedia/meta/w',
});
For backward compatibility, you can specify up to two parameters:
$bot->set_wiki($host, $path);
This form is deprecated and will emit deprecation warnings.
login
This method takes a hashref with keys username and password at a minimum.
See "Single User Login" and "Basic authentication" for additional options.
Logs the $username in, optionally using $password. First, an attempt will be made to use cookies to log in. If this fails, an attempt will be made to use the password provided to log in, if any. If the login was successful, returns true; false otherwise.
$bot->login({
username => $username,
password => $password,
}) or die "Login failed";
Once logged in, attempt to do some simple auto-configuration. At present, this consists of:
- Warning if the account doesn't have the bot flag, and isn't a sysop account.
- Setting an appropriate default assert.
You can skip this autoconfiguration by passing autoconfig => 0
For backward compatibility, you can call this as
$bot->login($username, $password);
This form is deprecated, and will emit deprecation warnings. It will never do autoconfiguration or SUL login.
Single User Login
On WMF wikis, do_sul specifies whether to log in on all projects. The default
is false. But even when false, you still get a CentralAuth cookie for, and are
thus logged in on, all languages of a given domain (*.wikipedia.org, for example).
When set, a login is done on each WMF domain so you are logged in on all ~800
content wikis. Since *.wikimedia.org is not possible, we explicitly include
meta, commons, incubator, and wikispecies.
Basic authentication
If you need to supply basic auth credentials, pass a hashref of data as described by LWP::UserAgent:
$bot->login({
username => $username,
password => $password,
basic_auth => { netloc => "private.wiki.com:80",
realm => "Authentication Realm",
uname => "Basic auth username",
pass => "password",
}
}) or die "Couldn't log in";
Bot passwords
MediaWiki::Bot doesn't yet support the more complicated (but more secure)
oAuth login flow for bots. Instead, we support a simpler "bot password", which
is a generated password connected to a (possibly-reduced) set of on-wiki
privileges, and IP ranges from which it can be used.
To create one, visit Special:BotPasswords on the wiki. Enter a label for
the password, then select the privileges you want to use with that password.
This set should be as restricted as possible; most bots only edit existing
pages. Keeping the set of privileges as restricted as possible limits the
possible damage if the password were ever compromised.
Submit the form, and you'll be given a new "username" that looks like
"AccountUsername@bot_password_label", and a generated bot password.
To log in, provide those to MediaWiki::Bot verbatim.
References: API:Login, Logging in
logout
$bot->logout();
The logout method logs the bot out of the wiki. This invalidates all login cookies.
References: API:Logging out
Getting information about pages
diff
This allows retrieval of a diff from the API. The return is a scalar containing the HTML table of the diff. Options are passed as a hashref with keys:
- title is the title to use. Provide either this or revid.
- revid is any revid to diff from. If you also specified title, only title will be honoured.
- oldid is an identifier to diff to. This can be a revid, or the special values 'cur', 'prev' or 'next'
References: API:Properties#revisions
get_history
my @hist = $bot->get_history($title);
my @hist = $bot->get_history($title, $additional_params);
Returns an array containing the history of the specified page $title.
The optional hash ref $additional_params can be used to tune the query by API parameters, such as 'rvlimit' to return only 'rvlimit' number of revisions (default is as many as possible, but may be limited per query) or 'rvdir' to set the chronological direction.
Example:
my @hist = $bot->get_history('Main Page', {'rvlimit' => 10, 'rvdir' => 'older'})
The array returned contains hashrefs with keys: revid, user, comment, minor, timestamp_date, and timestamp_time.
For backward compatibility, you can specify up to four parameters:
my @hist = $bot->get_history($title, $limit, $revid, $direction);
This form is deprecated, and will emit deprecation warnings.
References: Getting page history, API:Properties#revisions
get_history_step_by_step
my @hist = $bot->get_history_step_by_step($title);
my @hist = $bot->get_history_step_by_step($title, $additional_params);
Same as get_history(), but does not return the full history at once, but let's you loop through it.
The optional call-by-reference hash ref $additional_params can be used to loop through a page's full history by using the 'continue' param returned by the API.
Example:
my $ready;
my $filter_params = {};
while(!$ready){
my @hist = $bot->get_history_step_by_step($page, $filter_params);
if(@hist == 0 || !defined($filter_params->{'continue'})){
$ready = 1;
}
# do something with @hist
}
References: Getting page history, API:Properties#revisions
what_links_here
Returns an array containing a list of all pages linking to $page.
Additional optional parameters are:
- One of:
all(default),redirects, ornonredirects. - A namespace number to search (pass an arrayref to search in multiple namespaces)
- An "Options hashref".
A typical query:
my @links = $bot->what_links_here("Meta:Sandbox",
undef, 1,
{ hook=>\&mysub }
);
sub mysub{
my ($res) = @_;
foreach my $hash (@$res) {
my $title = $hash->{'title'};
my $is_redir = $hash->{'redirect'};
print "Redirect: $title\n" if $is_redir;
print "Page: $title\n" unless $is_redir;
}
}
Transclusions are no longer handled by what_links_here() - use "list_transclusions" instead.
References: Listing incoming links, API:Backlinks
get_id
Returns the id of the specified $page_title. Returns undef if page does not exist.
my $pageid = $bot->get_id("Main Page");
die "Page doesn't exist\n" if !defined($pageid);
Revisions: API:Properties#info
get_pages
Returns the text of the specified pages in a hashref. Content of undef means page does not exist. Also handles redirects or article names that use namespace aliases.
my @pages = ('Page 1', 'Page 2', 'Page 3');
my $thing = $bot->get_pages(\@pages);
foreach my $page (keys %$thing) {
my $text = $thing->{$page};
print "$text\n" if defined($text);
}
References: Fetching page text, API:Properties#revisions
prefixindex
This returns an array of hashrefs containing page titles that start with the given $prefix. The hashref has keys 'title' and 'redirect' (present if the page is a redirect, not present otherwise).
Additional parameters are:
-
One of
all,redirects, ornonredirects -
A single namespace number (unlike "linksearch" etc, which can accept an arrayref of numbers).
-
$options_hashref as described in "Options hashref".
my @prefix_pages = $bot->prefixindex("User:Mike.lifeguard");
Or, the more efficient equivalent
my @prefix_pages = $bot->prefixindex("Mike.lifeguard", 2); foreach my $hashref (@pages) { my $title = $hashref->{'title'}; if $hashref->{'redirect'} { print "$title is a redirect\n"; } else { print "$title\n is not a redirect\n"; } }
References: API:Allpages
get_protection
Returns data on page protection as a array of up to two hashrefs. Each hashref has a type, level, and expiry. Levels are 'sysop' and 'autoconfirmed'; types are 'move' and 'edit'; expiry is a timestamp. Additionally, the key 'cascade' will exist if cascading protection is used.
my $page = 'Main Page';
$bot->edit({
page => $page,
text => rand(),
summary => 'test',
}) unless $bot->get_protection($page);
You can also pass an arrayref of page titles to do bulk queries:
my @pages = ('Main Page', 'User:Mike.lifeguard', 'Project:Sandbox');
my $answer = $bot->get_protection(\@pages);
foreach my $title (keys %$answer) {
my $protected = $answer->{$title};
print "$title is protected\n" if $protected;
print "$title is unprotected\n" unless $protected;
}
References: API:Properties#info
get_last
Returns the revid of the last revision to $page not made by $user. undef
is returned if no result was found, as would be the case if the page is deleted.
my $revid = $bot->get_last('User:Mike.lifeguard/sandbox', 'Mike.lifeguard');
if defined($revid) {
print "Reverting to $revid\n";
$bot->revert('User:Mike.lifeguard', $revid, 'rvv');
}
References: API:Properties#revisions
recent_edit_to_page
my ($timestamp, $user) = $bot->recent_edit_to_page($title);
Returns timestamp and username for most recent (top) edit to $page.
References: API:Properties#revisions
get_users
my @recent_editors = $bot->get_users($title, $limit, $revid, $direction);
Gets the most recent editors to $page, up to $limit, starting from $revision
and going in $direction.
References: API:Properties#revisions
get_text
Returns the wikitext of the specified $page_title.
The first parameter $page_title is the only required one.
The second parameter is a hashref with the following independent optional keys:
rvstartid- if defined, this function returns the text of that revision, otherwise the newest revision will be used.rvsection- if defined, returns the text of that section. Otherwise the whole page text will be returned.pageid- this is an output parameter and can be used to fetch the id of a page without the need of calling "get_id" additionally. Note that the value of this param is ignored and it will be overwritten by this function.rv...- any param starting with 'rv' will be forwarded to the api call.
A blank page will return wikitext of "" (which evaluates to false in Perl, but is defined); a nonexistent page will return undef (which also evaluates to false in Perl, but is obviously undefined). You can distinguish between blank and nonexistent pages by using defined:
# simple example
my $wikitext = $bot->get_text('Page title');
print "Wikitext: $wikitext\n" if defined $wikitext;
# advanced example
my $options = {'revid'=>123456, 'section_number'=>2};
$wikitext = $bot->get_text('Page title', $options);
die "error, see API error message\n" unless defined $options->{'pageid'};
warn "page doesn't exist\n" if $options->{'pageid'} == MediaWiki::Bot::PAGE_NONEXISTENT;
print "Wikitext: $wikitext\n" if defined $wikitext;
References: Fetching page text, API:Properties#revisions
For backward-compatibility the params revid and section_number may also be
given as scalar parameters:
my $wikitext = $bot->get_text('Page title', 123456, 2);
print "Wikitext: $wikitext\n" if defined $wikitext;
This form is deprecated, and will emit deprecation warnings.
is_protected
This is a synonym for "get_protection", which should be used in preference.
This method is deprecated and will emit deprecation warnings.
Modifying pages
edit
my $text = $bot->get_text('My page');
$text .= "\n\n* More text\n";
$bot->edit({
page => 'My page',
text => $text,
summary => 'Adding new content',
section => 'new',
});
This method edits a wiki page, and takes a hashref of data with keys:
page- the page title to edittext- the page text to writesummary- an edit summaryminor- whether to mark the edit as minor or not (boolean)bot- whether to mark the edit as a bot edit (boolean)assertion- usually 'bot', but see http://mediawiki.org/wiki/Extension:AssertEdit.section- edit a single section (identified by number) instead of the whole page
An MD5 hash is sent to guard against data corruption while in transit.
You can also call this as:
$bot->edit($page, $text, $summary, $is_minor, $assert, $markasbot);
This form is deprecated and will emit deprecation warnings.
CAPTCHAs
If a CAPTCHA is encountered, the
call to edit will return false, with the error code set to ERR_CAPTCHA
and the details informing you that solving a CAPTCHA is required for this
action. The information you need to actually solve the captcha (for example
the URL for the image) is given in $bot->{error}->{captcha} as a
hash reference. You will want to grab the keys 'url' (a relative URL to
the image) and 'id' (the ID of the CAPTCHA). Once you have solved the
CAPTCHA (presumably by interacting with a human), retry the edit, adding
captcha_id and captcha_solution parameters:
my $edit = {page => 'Main Page', text => 'got your nose'};
my $edit_status = $bot->edit($edit);
if (not $edit_status) {
if ($bot->{error}{code} == ERR_CAPTCHA) {
my @captcha_uri = split /\Q?/, $bot->{error}{captcha}{url}, 2;
my $image = URI->new(sprintf '%s://%s%s?%s' =>
$bot->{protocol}, $bot->{host}, $captcha_uri[0], $captcha_uri[1],
);
require Term::ReadLine;
my $term = Term::ReadLine->new('Solve the captcha');
$term->ornaments(0);
my $answer = $term->readline("Please solve $image and type the answer: ");
# Add new CAPTCHA params to the edit we're attempting
$edit->{captcha_id} = $bot->{error}{captcha}{id};
$edit->{captcha_solution} = $answer;
$edit_status = $bot->edit($edit);
}
}
References: Editing pages, API:Edit, API:Tokens
move
$bot->move($from_title, $to_title, $reason, $options_hashref);
This moves a wiki page.
If you wish to specify more options (like whether to suppress creation of a
redirect), use $options_hashref, which has keys:
-
movetalkspecifies whether to attempt to the talk page. -
noredirectspecifies whether to suppress creation of a redirect. -
movesubpagesspecifies whether to move subpages, if applicable. -
watchandunwatchadd or remove the page and the redirect from your watchlist. -
ignorewarningsignores warnings.my @pages = ("Humor", "Rumor"); foreach my $page (@pages) { my $to = $page;