Skip to content

Instantly share code, notes, and snippets.

@Kaiepi
Last active July 30, 2019 12:13
Show Gist options
  • Save Kaiepi/50db432579cc67202328a63c071f9c78 to your computer and use it in GitHub Desktop.
Save Kaiepi/50db432579cc67202328a63c071f9c78 to your computer and use it in GitHub Desktop.
Pokémon Showdown Logs Scraper
# Instructions:
# - Save this as ps-logs-scraper.p6
# - Install Rakudo Star
# - Open up whatever terminal you use (cmd on Windows)
# - Enter "zef install Cro::HTTP JSON::Fast URI::Encode"
# - Change directory to wherever you saved this ("cd <directory>" on Windows)
# - Run perl6 ps-logs-scraper.p6 for usage instructions
#
# You will probably get a couple scary looking warnings beginning with
# "Trailing item in Hash.append" when running this script. Don't worry about this;
# this is due to Cro not being able to parse some of the cookies PS sets properly.
use v6.d;
use Cro::HTTP::Cookie;
use Cro::HTTP::Client;
use Cro::HTTP::Response;
use JSON::Fast;
use URI::Encode;
sub die(Str $message) {
note $message;
exit 1;
}
sub MAIN(
Str :$username!,
Str :$password!,
Str :$room!,
Str :$from!,
Str :$to!,
Str :$path = '.'
) {
my Cro::HTTP::Client $client .= new: :cookie-jar;
{
say 'Logging in...';
my Str $challstr = '4|' ~ (|'a'...'f', |'0'...'9').pick(256).join;
my Cro::HTTP::Response $response = await $client.post:
'https://play.pokemonshowdown.com/action.php',
http => 1.1,
content-type => 'application/x-www-form-urlencoded; charset=UTF-8',
body => %(:act<login>, :name($username), :pass($password), :$challstr);
my Str $data = await $response.body-text;
die $data unless $data.starts-with: ']';
my %data = from-json $data.substr: 1;
die 'Invalid username or password' unless %data<curuser><loggedin>;
die %data<assertion>.substr: 2 if %data<assertion>.starts-with: ';;';
}
{
say 'Getting assertion...';
my Cro::HTTP::Response $response = await $client.get:
'https://play.pokemonshowdown.com/action.php?act=getassertion&challengekeyid=2',
http => 1.1;
$client.cookie-jar.add-cookie: Cro::HTTP::Cookie.new:
name => 'assertion',
value => 'logs2.psim.us_' ~ (uri_encode_component await $response.body-text),
domain => 'logs2.psim.us',
path => '/';
}
{
my Str $roomid = $room.samemark(' ').subst(/ <-[a..z 0..9 -]>+ /, '', :g);
my Date $begin .= new: $from;
my Date $end .= new: $to;
my Str @dates = gather {
my Int $month = $begin.month;
for $begin.year..$end.year -> Int $year {
my Date $date .= new: :$year, :$month;
my Int $last-day = $year == $end.year && $month == $end.month
?? $end.day
!! $date.days-in-month;
for $begin.day..$last-day -> Int $day {
take Date.new(:$year, :$month, :$day).yyyy-mm-dd;
}
$month = $month == 12 ?? 1 !! $month + 1;
}
};
hyper for @dates -> Str $date {
say "Fetching logs for $room on $date...";
my Cro::HTTP::Response $response = await $client.get:
"http://logs2.psim.us:8080/$roomid/{$date.substr: 0, 7}/$date.txt",
http => 1.1,
content-type => 'text/plain;charset=utf-8';
die "The account given doesn't have access to logs in $roomid"
if $response.request.path eq '/getassertion.html';
say "Writing logs for $room on $date...";
spurt $path.IO.child("$date.txt"), await $response.body-text;
}
}
say 'Done!';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment