清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>> 
                    
#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
use 5.010001;
use WWW::Mechanize;
use WWW::Mechanize::Image;
use HTTP::Response;
use JSON::Tiny qw(decode_json encode_json);
$ENV {PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
binmode STDOUT, ":encoding(utf8)";
# 'http://stackoverflow.com/questions/6795030/how-to-ignore-certificate-verify-failed-error-in-perl'
# 'http://htmlparsing.com/perl.html'
# 'https://metacpan.org/pod/WWW::Mechanize#mech-put-uri-content-content'
# 'https://metacpan.org/pod/HTTP::Response'
# 'https://metacpan.org/pod/LWP::UserAgent'
# 'https://metacpan.org/pod/WWW::Mechanize::Image'
# 'http://www.perlmonks.org/?node_id=737473'
# 'http://stackoverflow.com/questions/10648754/how-do-i-simulate-this-particular-post-request-in-mechanize'
# 'https://kyfw.12306.cn/otn/login/init'
# 'http://dict.youdao.com'
my %url = (
	'unlogin' => {
		'init' => 'https://kyfw.12306.cn/otn/login/init',
		'getcode' => 'https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand&0.9890632561546399',
		'verifycode' => 'https://kyfw.12306.cn/otn/passcodeNew/checkRandCodeAnsyn',
		'login' => 'https://kyfw.12306.cn/otn/login/loginAysnSuggest',
	},
	'logined' => {
		'login' => 'https://kyfw.12306.cn/otn/login/userLogin',
		'init' => 'https://kyfw.12306.cn/otn/index/initMy12306',
		'queryinit' => 'https://kyfw.12306.cn/otn/lcxxcx/init',
		'logout' => 'https://kyfw.12306.cn/otn/login/loginOut',
	},
);
# query need fill in query data, such as date, from station ..
my $t = 'https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=%s&queryDate=%s&from_station=%s&to_station=%s',
my %info = (
	'account' 	=> '',
	'password'	=> '',
);
my %train = (
	one => {
		pc => 'ADULT',
		qd => '2016-02-06',
		fs => 'BJP',
		ts => 'JNK',
		rg => 'G\d+',
	},
	two => {
		pc => 'ADULT',
		qd => '2016-02-06',
		fs => 'JNK',
		ts => 'JIK',
		rg => '.*',
	}
);
my @train = getquery($t, \%train);
my $curr = undef;
our $localpath = 'password/';
#
#
if (! -e $localpath ) {
	mkdir($localpath);
}
# read password
{
	my $pwdata	= slurp($ARGV[0]);
	my $pwj 	= decode_json($pwdata);
	
	$info{password}	= $pwj->{password};
	$info{account}	= $pwj->{account};
}
#
# may be disconnect because of network..
#
###############################################################
my $mech = mechanize();
$mech->get($url{unlogin}{init});
check($mech->success(), "can not access homepage.");
my $localfile = localtime() .".jpg";
downloadImage($url{unlogin}{getcode}, $localfile, $mech);
my $size = -s $localpath.$localfile; # get picture size
if ($size <= 3 * 1024) {
	check (0, "picture size -> $size . try latter ..");
}
note("ready input verify code ");
# input such as 1,1 or 2,3 [cell's coordinate you want click on picture ] .
my $randcode = randGet();
note("Verify Code => ".$randcode);
sleep(5);
note("Post to verify");
my $content;
my $res = $mech->post($url{unlogin}{verifycode}, [ 'randCode' => $randcode, 'rand' => 'sjrand' ]);
if ($mech->success && $res->is_success) {
	$content = $res->decoded_content;
	if ($content =~ /TRUE/) {
		note("verify ok");
	} else {
		note("verify error -> " .  $content);
		check(0, " quit");
	}
	
} else {
	check(0, "can not get respone");
}
sleep(3);
note ("start login");
$res = $mech->post($url{unlogin}{login}, [ 'loginUserDTO.user_name' => $info{account}, 'userDTO.password' => $info{password}, 'randCode' => $randcode ]);
if ($mech->success && $res->is_success) {
	$content = $res->decoded_content;
} else {
	check(0, "can not get respone");
}
sleep(3);
note("login !!");
$res = $mech->post($url{logined}{login}, [ '_json_attr' => '' ]);
if ($mech->success && $res->is_success) {
	$content = $res->decoded_content;
} else {
	check(0, "can not get respone");
}
sleep(3);
note("init my 12306");
$mech->get($url{logined}{init});
check($mech->success(), "can not access ".$url{logined}{init});
sleep(3);
note("init lcxxcx");
$mech->get($url{logined}{queryinit});
check($mech->success(), "can not access ".$url{logined}{queryinit});
while (1) {
	if (! -e "run.flag") {
		last;
	}
	if (!defined($curr)) {
		$curr = shift @train;
	} else {
		sleep(5);
		note("query ...");
		$mech->get($curr);
		check($mech->success(), "can not access ".$curr);
	
		my @tickets = gettickets(decode_json($mech->content));
	
		say join("\t", ("车次", "始发", "终点", "出发", "目的", "开车", "到站", "历时", "二等座", "硬座"));
		for my $ticket (@tickets) {
			say join("\t", (
				$ticket->{station_train_code},
				$ticket->{start_station_name},
				$ticket->{end_station_name},
				$ticket->{from_station_name},
				$ticket->{from_station_name},
				$ticket->{to_station_name},
				$ticket->{from_station_name},
				$ticket->{to_station_name},
				$ticket->{lishi},
				$ticket->{'ze_num'},
				$ticket->{'yz_num'},
			));
		}
	}
}
sleep(3);
note("loginOut");
$mech->get($url{logined}{logout});
check($mech->success(), "can not access ".$url{logined}{logout});
exit;
#####################################
#$info{train} = $term->{station_train_code};
#$info{start} = $term->{start_station_name};
#$info{end}   = $term->{end_station_name};
#$info{from} = $term->{from_station_name};
#$info{to}   = $term->{to_station_name};
#$info{start_time} = $term->{from_station_name};
#$info{arrive_time} = $term->{to_station_name};
#$info{time} = $term->{lishi};
#$info{'seat-g'} = $term->{'ze_num'};
#$info{'seat-y'} = $term->{'yz_num'};
sub gettickets {
	my $json = shift;
	
	if (! $json->{status}) {
		return undef;
	}
	
	my $data = $json->{data};
	
	my @all;
	
	for my $term (@{$data->{datas}}) {
		push @all, $term;
	}
	
	return @all;
}
sub getquery {
	my $template = shift;
	my $train = shift;
	my @all;
	for (keys %{$train}) {
		my $o = $train->{$_};
	
		my $str = sprintf $t, $o->{pc}, $o->{qd}, $o->{fs}, $o->{ts};
	
		push @all, $str;
	}
	
	return @all;
}
sub slurp {
	my $file = shift;
	
	open my $fh, '<', $file or die "Open $file failed!";
	
	local $/ = undef;
	
	my $data = <$fh>;
	
	close $fh;
	
	return $data;
}
sub getline {
	while(<STDIN>) {
		chomp;
		return $_;
	}
}
sub randGet {
	my $verify_code = "";
	
	while (<STDIN>) {
		chomp;
		if (/\A\Z/) {
			return $verify_code;
		} else {
			if ($verify_code =~ /\A\Z/) {
				$verify_code = point(split(/,/, $_));
			} else {
				$verify_code = $verify_code . ',' . point(split(/,/, $_));
			}
		}
	}
}
sub point {
	my ($y, $x) = @_;
	my $rx = ($x - 1) * 73 + 36;
	my $ry = ($y - 1) * 95 + 47;
	
	return "$rx,$ry";
}
sub downloadImage {
	my ($url, $local, $mech) = @_;
	
	if (!defined($mech)) {
		$mech = mechanize();
	}
	
	if ($url) {
		$mech->get($url, ':content_file' => $localpath.$local);
		
		check($mech->success(), "can not get image -> ".$url);
	} else {
		check(0, "image is null");
	}
}
sub mechanize {
	my $mech = WWW::Mechanize->new('ssl_opts' => { 'verify_hostname' => 0, SSL_verify_mode => 'SSL_VERIFY_NONE' });
	### settings
	$mech->agent_alias('Windows Mozilla');
	
	return $mech;
}
sub note {
	my $str = shift;
	
	say "+ -> $str";
}
sub check {
	my ($bool, $msg) = @_;
	
	unless ($bool) {
		print $msg."\n";
		exit(1);
	}
}
																		