Mercurial > eagle-eye
comparison Ikariam.pm @ 101:592d3b3b7898
implemented the WAR robot
author | "Rex Tsai <chihchun@kalug.linux.org.tw>" |
---|---|
date | Wed, 29 Oct 2008 12:05:36 +0800 |
parents | ed6160630329 |
children | b369fe3c1992 |
comparison
equal
deleted
inserted
replaced
100:ed6160630329 | 101:592d3b3b7898 |
---|---|
6 } | 6 } |
7 | 7 |
8 use Class::DBI::AutoLoader ( | 8 use Class::DBI::AutoLoader ( |
9 dsn => 'dbi:SQLite:dbname=ikariam.sqlite', | 9 dsn => 'dbi:SQLite:dbname=ikariam.sqlite', |
10 options => { RaiseError => 1 }, | 10 options => { RaiseError => 1 }, |
11 tables => ['cities', 'island', 'user', 'ally'], | 11 tables => ['cities', 'island', 'user', 'ally', 'report'], |
12 use_base => 'Class::DBI::SQLite', | 12 use_base => 'Class::DBI::SQLite', |
13 namespace => 'Ikariam', | 13 namespace => 'Ikariam', |
14 ); | 14 ); |
15 | 15 |
16 package Ikariam::Extractor; | 16 package Ikariam::Extractor; |
95 use HTTP::Cookies; | 95 use HTTP::Cookies; |
96 use WWW::Mechanize; | 96 use WWW::Mechanize; |
97 use HTML::TagParser; | 97 use HTML::TagParser; |
98 use XML::LibXML qw(:encoding); | 98 use XML::LibXML qw(:encoding); |
99 use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; | 99 use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; |
100 # use Time::ParseDate; | |
101 use POSIX; | |
100 use utf8; | 102 use utf8; |
101 | 103 |
102 sub new | 104 sub new |
103 { | 105 { |
104 my ($class, $server, $user, $pass) = @_; | 106 my ($class, $server, $user, $pass) = @_; |
175 searchUser => $user, | 177 searchUser => $user, |
176 view => 'highscore' | 178 view => 'highscore' |
177 ]); | 179 ]); |
178 my $extractor = new Ikariam::Extractor(content => $res->content); | 180 my $extractor = new Ikariam::Extractor(content => $res->content); |
179 my $result = $extractor->{doc}->find('//table[@class="table01"][2]//tr'); | 181 my $result = $extractor->{doc}->find('//table[@class="table01"][2]//tr'); |
182 | |
180 foreach my $tr ( @$result ) { | 183 foreach my $tr ( @$result ) { |
181 my %user; | 184 my %user; |
182 | 185 my $extractor = new Ikariam::Extractor(content => $tr->toString(1)); |
183 $extractor->{doc} = $tr; | 186 |
184 my $href = $extractor->find('//td[@class="action"]/a/@href'); | 187 my $href = $extractor->find('//td[@class="action"]/a/@href'); |
185 if($href =~ /index\.php\?view=sendMessage&with=(\d+)&oldView=highscore/) { | 188 if($href =~ /index\.php\?view=sendMessage&with=(\d+)&oldView=highscore/) { |
186 $user{'id'} = $1; | 189 $user{'id'} = $1; |
187 # $user{'name'} = $extractor->find('//td[@class="name"]'); | |
188 $user{'name'} = $user; | 190 $user{'name'} = $user; |
191 $user{'name'} = $extractor->find('//td[@class="name"]'); | |
189 | 192 |
190 $user{'ally'} = $extractor->find('//td[@class="allytag"]/a/text()'); | 193 $user{'ally'} = $extractor->find('//td[@class="allytag"]/a/text()'); |
191 my $allyHref = $extractor->find('//td[@class="allytag"]/a/@href'); | 194 my $allyHref = $extractor->find('//td[@class="allytag"]/a/@href'); |
192 if($allyHref =~ /\?view=allyPage&oldView=highscore&allyId=(\d+)/) { | 195 if($allyHref =~ /\?view=allyPage&oldView=highscore&allyId=(\d+)/) { |
193 $user{'allyId'} = $1; | 196 $user{'allyId'} = $1; |
195 $user{$type} = $extractor->find('//td[@class="score"]/text()'); | 198 $user{$type} = $extractor->find('//td[@class="score"]/text()'); |
196 $user{$type} =~ s/,//g; | 199 $user{$type} =~ s/,//g; |
197 $users{$user{'id'}} = \%user; | 200 $users{$user{'id'}} = \%user; |
198 } | 201 } |
199 } | 202 } |
203 # print(Dumper(\%users)); | |
200 return \%users; | 204 return \%users; |
201 } | 205 } |
202 | 206 |
203 sub viewWorldMap | 207 sub viewWorldMap |
204 { | 208 { |
410 } | 414 } |
411 } | 415 } |
412 return $out; | 416 return $out; |
413 } | 417 } |
414 | 418 |
415 sub checkCity { | 419 sub plunderCity { |
416 my $self = shift; | 420 my $self = shift; |
417 my $cityId = shift; | 421 my $cityId = shift; |
418 | 422 $self->{mech}->get(sprintf("http://%s/index.php?view=plunder&destinationCityId=%d", $self->{server}, $cityId)); |
419 # search for goods | 423 $self->{mech}->submit_form( |
424 form_number => 1, | |
425 fields => { | |
426 cargo_army_302 => '2', | |
427 } | |
428 ); | |
429 } | |
430 | |
431 sub changeCity { | |
432 my $self = shift; | |
433 my $cityId = shift; | |
434 | |
420 $self->{mech}->get(sprintf("http://%s/index.php", $self->{server})); | 435 $self->{mech}->get(sprintf("http://%s/index.php", $self->{server})); |
421 $self->{mech}->submit_form( | 436 $self->{mech}->submit_form( |
422 form_number => 2, | 437 form_number => 2, |
423 fields => { | 438 fields => { |
424 cityId => $cityId, | 439 cityId => $cityId, |
425 } | 440 } |
426 ); | 441 ); |
442 } | |
443 | |
444 sub checkCity { | |
445 my $self = shift; | |
446 my $cityId = shift; | |
447 | |
448 $self->changeCity($cityId); | |
449 | |
427 my $res = $self->{mech}->get(sprintf("http://%s/index.php?view=city&id=%d", $self->{server}, $cityId)); | 450 my $res = $self->{mech}->get(sprintf("http://%s/index.php?view=city&id=%d", $self->{server}, $cityId)); |
428 my $extractor = new Ikariam::Extractor(content => $res->content); | 451 my $extractor = new Ikariam::Extractor(content => $res->content); |
429 | 452 |
430 $self->{'cities'}->{$cityId}->{resources}->{gold} = $extractor->find('//span[@id="value_gold"]/text()'); | 453 $self->{'cities'}->{$cityId}->{resources}->{gold} = $extractor->find('//span[@id="value_gold"]/text()'); |
431 $self->{'cities'}->{$cityId}->{resources}->{gold} =~ s/,//g; | 454 $self->{'cities'}->{$cityId}->{resources}->{gold} =~ s/,//g; |
476 | 499 |
477 | 500 |
478 sub checkMilitaryAdvisorMilitaryMovements { | 501 sub checkMilitaryAdvisorMilitaryMovements { |
479 my $self = shift; | 502 my $self = shift; |
480 # TODO | 503 # TODO |
481 # http://%s/index.php?view=militaryAdvisorMilitaryMovements | |
482 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorMilitaryMovements', $self->{server})); | 504 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorMilitaryMovements', $self->{server})); |
483 my $extractor = new Ikariam::Extractor(content => $res->content); | 505 my $extractor = new Ikariam::Extractor(content => $res->content); |
484 | 506 |
485 my @homeland = $extractor->find('//div[@id="homeland"]'); | 507 $self->{'military'}->{wars} = 0; |
486 my @elsewhere = $extractor->find('//div[@id="elsewhere"]'); | 508 $self->{'military'}->{attack} = 0; |
487 $self->{'military'}->{attacks} = $#elsewhere+1; | 509 |
488 $self->{'military'}->{wars} = $#homeland+1; | 510 foreach (qw/homeland elsewhere/) { |
489 | 511 $self->{'military'}->{$_} = (); |
490 # there are some details. | 512 my $result = $extractor->{doc}->find(sprintf('//div[@id="%s"]//ul[@id="battleReports"]/li[@class="enroute"]', $_)); |
491 #<div id="homeland" class="content"> | 513 foreach my $div ( @$result ) { |
492 # <ul id="battleReports"> | 514 my $extractor = new Ikariam::Extractor(content => $div->toString(1)); |
493 # <li class="groundfight"> | 515 my $f = $extractor->find('//div[@class="report"]/a[1]/@href'); |
494 # <div class="type"/> | 516 my $t = $extractor->find('//div[@class="report"]/a[2]/@href'), |
495 # <div class="report"> | 517 $f = $1 if($f =~ /\?view=island&cityId=(\d+)/); |
496 # <table cellspacing="0" cellpadding="0" class="repTable"> | 518 $t = $1 if($t =~ /\?view=island&cityId=(\d+)/); |
497 # <tbody><tr> | 519 |
498 # <th colspan="2"> | 520 push @{$self->{'military'}->{$_}}, { from => $f, to => $t}; |
499 # 攻擊 卍严破碎虛空焱卐 </th> | 521 if($_ eq 'homeland') { |
500 # </tr> | 522 $self->{'military'}->{wars}++; |
501 # </tbody></table> | 523 } else { |
502 # </div> | 524 $self->{'military'}->{attack}++; |
503 # <br class="clearfloat"/> | 525 } |
504 # </li> | 526 } |
505 # <li class="enroute" style="height: 52px;"> | 527 } |
506 # <script type="text/javascript"> | 528 # print(Dumper($self->{'military'})); |
507 # Event.onDOMReady(function() { | 529 } |
508 # getCountdown({ | 530 |
509 # enddate: 1224863393, | 531 sub checkMilitaryAdvisorReportView { |
510 # currentdate: 1224862910, | 532 my $self = shift; |
511 # el: "researchCountDown11396440" | 533 my $combatId = shift; |
512 # }, 3, " ", "", true, true); | 534 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorReportView&detailedCombatId=%s', $self->{server}, $combatId)); |
513 # }); | 535 my $extractor = new Ikariam::Extractor(content => $res->content); |
514 # </script> | 536 |
515 # <div class="type"> | 537 my %report; |
516 # <div id="researchCountDown11396440" class="time">5分 46秒</div><div class="undefined"> Finished 23:49:23</div> | 538 |
517 # </div> | 539 $report{id} = $combatId; |
518 # <div class="report"> | 540 my $c = $extractor->{doc}->toString(1); |
519 #來自 <a href="?view=island&cityId=98496">松鼠城</a> 的 3 兵力正在前往 <a href="?view=island&cityId=82959">卍严破碎虛空焱卐</a> 的途中。 </div> | 541 |
520 # <div class="action"> | 542 # FIXME 城鎮 6 級)的城牆( 2 級)為防禦部隊增加了 7% 的防禦力。 |
521 # <div class="return"> | 543 while($c =~ /城鎮\s+(\d+)/gs) { |
522 # <a href="?action=transportOperations&function=forceReturn&actionRequest=46cc5fdb56b8cb0e65e2116ff9f61512&eventId=11396440&oldView=militaryAdvisorMilitaryMovements" title="返回">返回</a> | 544 $report{cityLevel} = $1; |
523 # </div> | 545 $report{wallLevel} = $2; |
524 # </div> | 546 } |
525 # <br class="clearfloat"/> | 547 |
526 # </li> | 548 $report{attacker} = $extractor->find('//div[@id="troopsReport"]//table[@id="result"]//th[@class="attackers"]'); |
527 # </ul> | 549 $report{defender} = $extractor->find('//div[@id="troopsReport"]//table[@id="result"]//th[@class="defenders"]'); |
528 #</div> | 550 $report{winner} = $extractor->find('//div[@id="troopsReport"]//table[@id="result"]//td[@class="winner"]'); |
529 | 551 |
530 | 552 $report{targetCity} = $extractor->find('//div[@id="troopsReport"]/div/h3/a/text()'); |
531 # <div id="elsewhere" class="content"> | 553 my $href = $extractor->find('//div[@id="troopsReport"]/div/h3/a/@href'); |
532 # <ul id="battleReports"> | 554 if($href =~ /index\.php\?view=island&id=(\d+)&selectCity=(\d+)/) { |
533 # <li class="groundfight"> | 555 $report{island} = $1; |
534 # <div class="type"/> | 556 $report{city} = $2; |
535 # <div class="report"> | 557 } |
536 # <table cellspacing="0" cellpadding="0" class="repTable"> | 558 $report{gold} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="gold"]'); |
537 # <tbody><tr> | 559 $report{wood} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="wood"]'); |
538 # <th colspan="2"> | 560 $report{crystal} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="glass"]'); |
539 # 攻擊 Rex </th> | 561 $report{wine} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="wine"]'); |
540 # </tr> | 562 $report{sulfur} = $extractor->find('//div[@id="troopsReport"]//ul[@class="resources"]/li[@class="sulfur"]'); |
541 # </tbody></table> | 563 |
542 # </div> | 564 foreach(qw/gold wood crystal wine sulfur attacker defender winner/) { |
543 # <br class="clearfloat"/> | 565 $report{$_} =~ s/^.*?:\s+//; |
544 # </li> | 566 $report{$_} =~ s/\s+$//; |
545 # <li class="enroute"> | 567 $report{$_} =~ s/,//g; |
546 # <script type="text/javascript"> | 568 } |
547 # Event.onDOMReady(function() { | 569 return \%report; |
548 # getCountdown({ | |
549 # enddate: 1224877160, | |
550 # currentdate: 1224861666, | |
551 # el: "researchCountDown159638" | |
552 # }, 3, " ", "", true, true); | |
553 # }); | |
554 # </script> | |
555 # <div class="type"> | |
556 # <div id="researchCountDown159638" class="time">4時 17分 35秒</div> | |
557 # </div> | |
558 # <div class="report"> | |
559 #來自 <a href="?view=island&cityId=6078">水晶交換各種資源</a> 的 3 兵力正在前往 <a href="?view=island&cityId=6077">Rex</a> 的途中。 </div> | |
560 # </li> | |
561 # </ul> | |
562 # </div> | |
563 } | 570 } |
564 | 571 |
565 sub checkMilitaryAdvisorCombatReports { | 572 sub checkMilitaryAdvisorCombatReports { |
566 my $self = shift; | 573 my $self = shift; |
567 my $content; | 574 my $page = shift || 0; |
568 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorCombatReports', $self->{server})); | 575 |
569 gunzip \$res->content => \$content | 576 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorCombatReports&start=%s', $self->{server}, $page)); |
570 or die "gunzip failed: $GunzipError\n"; | 577 my $extractor = new Ikariam::Extractor(content => $res->content); |
571 | 578 |
572 # TODO | 579 my $result = $extractor->{doc}->find('//div[@id="troopsOverview"]//table/tr[position()<=10]'); |
573 | 580 foreach my $tr ( @$result ) { |
574 # list down reports. | 581 my $trExtractor = new Ikariam::Extractor(content => $tr->toString(1)); |
575 # /index.php?view=militaryAdvisorReportView&combatId=1887662 | 582 my $date = $trExtractor->find('//td[@class="date"]'); |
576 # //form[@id='finishedReports']//a | 583 $date =~ s/^\s+//g; $date =~ s/\s+$//g; |
584 | |
585 | |
586 my $href = $trExtractor->find('//td/a/@href'); | |
587 if($href =~ /index.php\?view=militaryAdvisorReportView&combatId=(\d+)/) { | |
588 my $report = Ikariam::Report->retrieve($1); | |
589 if(!$report) { | |
590 my $report_hash = $self->checkMilitaryAdvisorReportView($1); | |
591 $report = Ikariam::Report->insert($report_hash); | |
592 | |
593 if($date =~ /(\d+)\.(\d+)\. (\d+):(\d+)/) { | |
594 my $unixtime = mktime (0, $4, $3, $1, ($2-1), '108'); | |
595 $report->set('date', $unixtime); | |
596 } | |
597 $report->set('time', time); | |
598 | |
599 $report->update(); | |
600 } else { | |
601 return; | |
602 } | |
603 } else { | |
604 return; | |
605 } | |
606 } | |
607 | |
608 my @moreCombats = $extractor->find('//div[@id="troopsOverview"]//table/tr[position()>10]//a/@href'); | |
609 foreach (@moreCombats){ | |
610 last if(/^javascript/); | |
611 if(/\?view=militaryAdvisorCombatReports&start=(\d+)/) { | |
612 next if($1 le $page); | |
613 $self->checkMilitaryAdvisorCombatReports($1); | |
614 last; | |
615 } | |
616 } | |
577 } | 617 } |
578 | 618 |
579 sub checkTownHall { | 619 sub checkTownHall { |
580 my $self = shift; | 620 my $self = shift; |
581 my $cityId = shift; | 621 my $cityId = shift; |