Mercurial > eagle-eye
comparison Ikariam.pm @ 79:9d92e8c12f58
rewrited the code in XPath.
author | "Rex Tsai <chihchun@kalug.linux.org.tw>" |
---|---|
date | Fri, 24 Oct 2008 21:46:33 +0800 |
parents | 3d1784140009 |
children | 7ab5fc8c847c |
comparison
equal
deleted
inserted
replaced
78:4120f560f214 | 79:9d92e8c12f58 |
---|---|
10 options => { RaiseError => 1 }, | 10 options => { RaiseError => 1 }, |
11 tables => ['cities', 'island', 'user'], | 11 tables => ['cities', 'island', 'user'], |
12 use_base => 'Class::DBI::SQLite', | 12 use_base => 'Class::DBI::SQLite', |
13 namespace => 'Ikariam', | 13 namespace => 'Ikariam', |
14 ); | 14 ); |
15 | |
16 package Ikariam::Extractor; | |
17 use strict; | |
18 use Data::Dumper; | |
19 use XML::LibXML; | |
20 use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; | |
21 use Carp; | |
22 use utf8; | |
23 | |
24 sub new { | |
25 Carp::croak("Options should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH'; | |
26 | |
27 my($class, %conf) = @_; | |
28 | |
29 my $self = bless { | |
30 doc => undef, | |
31 gzip => 1, | |
32 }, $class; | |
33 | |
34 $self->{gzip} = $conf{'gzip'} if(defined($conf{'gzip'})); | |
35 $self->parse($conf{'content'}) if(defined($conf{'content'})); | |
36 | |
37 return $self; | |
38 } | |
39 | |
40 # parse($Content); | |
41 sub parse { | |
42 my ($self, $content) = @_; | |
43 my $string; | |
44 my $parser = XML::LibXML->new('1.0','utf-8'); | |
45 | |
46 if($self->{gzip} == 1) { | |
47 gunzip \$content => \$string | |
48 or die "gunzip failed: $GunzipError\n"; | |
49 } else { | |
50 $string = $content; | |
51 } | |
52 | |
53 $self->{doc} = $parser->parse_html_string ($string, { suppress_errors => 1 }); | |
54 return; | |
55 } | |
56 | |
57 # find($XPathQuery); | |
58 sub find { | |
59 my $self = shift; | |
60 my $query = shift; | |
61 my $out = []; | |
62 | |
63 my $result = $self->{doc}->find($query); | |
64 | |
65 return undef unless defined($result); | |
66 | |
67 if ( $result->isa( 'XML::LibXML::NodeList' ) ) { | |
68 return undef if($result->size() == 0); | |
69 foreach ( @$result ) { | |
70 # $_ is XML::LibXML::Element, XML::LibXML::Node | |
71 my $literal = $_->to_literal() , "\n"; | |
72 utf8::encode($literal); | |
73 # warn $_->toString(1) , "\n"; | |
74 return $literal unless wantarray; | |
75 push( @$out, $literal); | |
76 } | |
77 } else { | |
78 Carp::croak("Unsupported data type"); | |
79 } | |
80 # TODO | |
81 # XML::LibXML::Literal | |
82 # XML::LibXML::Boolean | |
83 | |
84 return @$out; | |
85 } | |
86 | |
87 1; | |
15 | 88 |
16 package Ikariam; | 89 package Ikariam; |
17 use strict; | 90 use strict; |
18 use Data::Dumper; | 91 use Data::Dumper; |
19 use LWP; | 92 use LWP; |
20 # use LWP::Debug qw(+ -conns -trace -debug); | 93 # use LWP::Debug qw(+ -conns -trace -debug); |
21 # use LWP::Debug qw(+trace); | 94 # use LWP::Debug qw(+trace); |
22 use HTTP::Cookies; | 95 use HTTP::Cookies; |
23 use WWW::Mechanize; | 96 use WWW::Mechanize; |
24 use HTML::TagParser; | 97 use HTML::TagParser; |
98 use XML::LibXML qw(:encoding); | |
25 use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; | 99 use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ; |
100 use utf8; | |
26 | 101 |
27 sub new | 102 sub new |
28 { | 103 { |
29 my ($class, $server, $user, $pass) = @_; | 104 my ($class, $server, $user, $pass) = @_; |
30 | 105 |
345 sub checkResearch { | 420 sub checkResearch { |
346 my $self = shift; | 421 my $self = shift; |
347 my $cityId = shift; | 422 my $cityId = shift; |
348 | 423 |
349 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=researchOverview&id=%s', $self->{server}, $cityId)); | 424 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=researchOverview&id=%s', $self->{server}, $cityId)); |
350 | 425 |
426 my @urls = Ikariam::Extractor->new(content => $res->content)->find('//ul[@class="explored"]//a/@href'); | |
427 my $out = {}; | |
428 foreach(@urls) { | |
429 if(/view=researchDetail&id=\d+&position=\d+&researchId=(\d+)$/) { | |
430 # we ignore the chinese name of technology researched. | |
431 @$out{$1} = 1; | |
432 } | |
433 } | |
434 return $out; | |
435 } | |
436 | |
437 sub checkCity { | |
438 my $self = shift; | |
439 my $cityId = shift; | |
440 | |
441 # search for goods | |
442 my $res = $self->{mech}->get(sprintf("http://%s/index.php?view=city&id=%d", $self->{server}, $cityId)); | |
443 my $extractor = new Ikariam::Extractor(content => $res->content); | |
444 | |
445 $self->{'cities'}->{$cityId}->{resources}->{gold} = $extractor->find('//span[@id="value_gold"]/text()'); | |
446 $self->{'cities'}->{$cityId}->{resources}->{gold} =~ s/,//g; | |
447 | |
448 $self->{'cities'}->{$cityId}->{name} = $extractor->find('//span[@class="city"]/text()'); | |
449 | |
450 $self->{'cities'}->{$cityId}->{construction} = defined($extractor->find('//*[@class="constructionSite"]')) ? 1 : 0; | |
451 | |
452 # maxCapacity | |
453 my $page = $extractor->{doc}->toString(1); | |
454 if($page =~ /maxCapacity : {\s+wood: (\d+),\s+wine: (\d+),\s+marble: (\d+),\s+crystal: (\d+),\s+sulfur: (\d+)\s+}/s) { | |
455 $self->{'cities'}->{$cityId}->{maxCapacity}->{wood} = $1; | |
456 $self->{'cities'}->{$cityId}->{maxCapacity}->{wine} = $2; | |
457 $self->{'cities'}->{$cityId}->{maxCapacity}->{marble} = $3; | |
458 $self->{'cities'}->{$cityId}->{maxCapacity}->{crystal} = $4; | |
459 $self->{'cities'}->{$cityId}->{maxCapacity}->{sulfur} = $5; | |
460 } | |
461 | |
462 foreach my $good (qw/wood wine marble crystal sulfur/) { | |
463 $self->{'cities'}->{$cityId}->{resources}->{$good} = $extractor->find(sprintf('//span[@id="value_%s"]', $good)); | |
464 $self->{'cities'}->{$cityId}->{resources}->{$good} =~ s/,//g; | |
465 } | |
466 | |
467 foreach my $i (0..14) { | |
468 my @buildings = $extractor->find(sprintf('//*[@id="position%s"]/@class', $i)); | |
469 foreach my $building (@buildings) { | |
470 if (!($building =~ /buildingGround/) && !($building =~ /townhall/)) { | |
471 $self->{'cities'}->{$cityId}->{locations}[$i] = $building; | |
472 | |
473 my $span; | |
474 if($building eq 'townHall') { | |
475 # this is stupid, the new vession give two cityTown information. | |
476 $span = ($extractor->find(sprintf('//*[@id="position%s"]//span[@class="textLabel"]/text()', $i)))[1]; | |
477 } else { | |
478 $span = $extractor->find(sprintf('//*[@id="position%s"]//span[@class="textLabel"]/text()', $i)); | |
479 } | |
480 my (undef, undef, $level) = split(/ /, $span); | |
481 $self->{'cities'}->{$cityId}->{buildings}->{$building} = $level; | |
482 } | |
483 } | |
484 } | |
485 | |
486 $self->{'cities'}->{$cityId}->{transporters}->{avail} = $extractor->find('//span[@id="value_transAvail"]/text()'); | |
487 $self->{'cities'}->{$cityId}->{transporters}->{sum} = $extractor->find('//span[@id="value_transSum"]/text()'); | |
488 $self->{'cities'}->{$cityId}->{transporters}->{sum} =~ s/[\(|\)]//g; | |
489 $self->{'cities'}->{$cityId}->{maxActionPoints} = $extractor->find('//span[@id="value_maxActionPoints"]');; | |
490 } | |
491 | |
492 | |
493 sub checkMilitaryAdvisorMilitaryMovements { | |
494 my $self = shift; | |
495 # TODO | |
496 # http://s2.ikariam.tw/index.php?view=militaryAdvisorMilitaryMovements | |
497 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorMilitaryMovements', $self->{server})); | |
498 } | |
499 | |
500 sub checkMilitaryAdvisorCombatReports { | |
501 my $self = shift; | |
351 my $content; | 502 my $content; |
503 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorCombatReports', $self->{server})); | |
352 gunzip \$res->content => \$content | 504 gunzip \$res->content => \$content |
353 or die "gunzip failed: $GunzipError\n"; | 505 or die "gunzip failed: $GunzipError\n"; |
354 my $html = HTML::TagParser->new($content); | 506 |
355 | 507 open(OUT,">foo.html"); |
356 my @elems = $html->getElementsByAttribute('class', 'explored'); | 508 print OUT $content; |
357 | 509 close(OUT); |
358 my $out = {}; | 510 |
359 foreach my $elem (@elems) { | 511 # TODO |
360 my @items = getElementsByTagName($elem, "a"); | 512 # $self->{'cities'}->{$cityId}->{force}->{attacks} = $1 if($content =~ /敵人攻擊: (\d+)/); |
361 foreach my $item (@items) { | 513 # $self->{'cities'}->{$cityId}->{force}->{wars} = $1 if($content =~ /我方軍隊行程: (\d+)/); |
362 if($item->getAttribute('href') =~ /view=researchDetail&id=\d+&position=\d+&researchId=(\d+)$/) { | 514 |
363 @$out{$1} = $item->innerText(); | 515 # list down reports. |
516 # /index.php?view=militaryAdvisorReportView&combatId=1887662 | |
517 # //form[@id='finishedReports']//a | |
518 } | |
519 | |
520 sub checkTownHall { | |
521 my $self = shift; | |
522 my $cityId = shift; | |
523 | |
524 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=townHall&id=%d', $self->{server}, $cityId)); | |
525 my $extractor = new Ikariam::Extractor(content => $res->content); | |
526 | |
527 # //div[@id='SatisfactionOverview']//div[@class='value'] | |
528 # //div[@id='SatisfactionOverview']//div[@class='text'] | |
529 $self->{"cities"}->{$cityId}->{happiness} = $extractor->find('//div[@id="SatisfactionOverview"]//div[@class="value"]'); | |
530 | |
531 # 取 SatisfactionOverview 中的其他值 | |
532 # 一個城鎮的市民滿意度結合了多方面的因素 | |
533 # check happiness | |
534 # Happiness = Basic bonuses (196 + Capital Bonus + Holiday Bonus(25)) + | |
535 # Wine (Tavern Base(12*level) + | |
536 # Tavern Bonus(80*step)) + | |
537 # Culture (Museum Base(20*level) + | |
538 # Cultural Goods Bonus(50*Cultural Goods)) - | |
539 # Population (population) - | |
540 # Corruption (Corruption rate * population) | |
541 # | |
542 # Growth Rate = Happiness * 0.02 | |
543 | |
544 # Space, 房屋數 | |
545 $self->{'cities'}->{$cityId}->{"space"} = {}; | |
546 $self->{'cities'}->{$cityId}->{"space"}->{'total'} = $extractor->find('//span[@class="value total"]/text()'); | |
547 $self->{'cities'}->{$cityId}->{"space"}->{'occupied'} = $extractor->find('//span[@class="value occupied"]/text()'); | |
548 | |
549 my @values = $extractor->find('//div[@id="CityOverview"]//span[@class="value"]'); | |
550 $self->{'cities'}->{$cityId}->{"growth"} = $values[0]; | |
551 $self->{'cities'}->{$cityId}->{"incomegold"} = $values[1]; | |
552 | |
553 $self->{'cities'}->{$cityId}->{corruption} = $extractor->find('//li[@class="corruption"]//span[@title="目前腐敗程度"]'); | |
554 $self->{'cities'}->{$cityId}->{corruption} =~ s/%//g; | |
555 | |
556 my @citizens_type = qw/citizens woodworkers specialworkers scientists/; | |
557 @values = $extractor->find('//div[@id="PopulationGraph"]//span[@class="count"]'); | |
558 foreach my $i (0..$#citizens_type) | |
559 { | |
560 $self->{'cities'}->{$cityId}->{'citizens'}->{$citizens_type[$i]} = $values[$i]; | |
561 $self->{'cities'}->{$cityId}->{'citizens'}->{total} += $values[$i]; | |
562 } | |
563 } | |
564 | |
565 | |
566 sub checkArmies | |
567 { | |
568 my $self = shift; | |
569 my $cityId = shift; | |
570 my %force_types; | |
571 | |
572 $force_types{'army'} = [ qw/undef undef Slinger Swordsman Phalanx Ram Archer Catapult Gunsman Mortar SteamGiant Gyrocopter Bombardier Doctor Cook/ ]; | |
573 $force_types{'fleet'} = [ qw/undef undef Ram-Ship BallistaShip Flamethrower CatapultShip MortarShip PaddleWheelRam DivingBoat/ ]; | |
574 | |
575 foreach my $x (qw/army fleet/) { | |
576 $self->{'cities'}->{$cityId}->{$x} = {}; | |
577 my $res = $self->{mech}->get(sprintf('http://%s/index.php?view=cityMilitary-%s&id=%d', $self->{server}, $x, $cityId)); | |
578 my @numbers = Ikariam::Extractor->new(content => $res->content)->find('//table//tr/td'); | |
579 foreach my $j (0..$#{$force_types{$x}}) { | |
580 if ($numbers[$j] == '-') { | |
581 $self->{'cities'}->{$cityId}->{$x}->{$force_types{$x}[$j]} = 0; | |
582 } else { | |
583 $self->{'cities'}->{$cityId}->{$x}->{$force_types{$x}[$j]} = $numbers[$j]; | |
364 } | 584 } |
365 } | 585 } |
366 } | 586 } |
367 return $out; | |
368 } | 587 } |
369 | 588 |
370 sub check | 589 sub check |
371 { | 590 { |
372 my $self = shift; | 591 my $self = shift; |
592 | |
593 # MilitaryAdvisor | |
594 $self->checkMilitaryAdvisorMilitaryMovements(); | |
595 $self->checkMilitaryAdvisorCombatReports(); | |
373 | 596 |
374 # looking for cities | 597 # looking for cities |
375 foreach my $cityId (keys(%{$self->{'cities'}})) | 598 foreach my $cityId (keys(%{$self->{'cities'}})) |
376 { | 599 { |
377 # search for goods | 600 $self->checkCity($cityId); |
378 my $res = $self->{mech}->post(sprintf('http://%s/index.php', $self->{server}), [ | 601 $self->checkTownHall($cityId); |
379 action => 'header', | 602 $self->checkArmies($cityId); |
380 cityId => $cityId, | |
381 function => 'changeCurrentCity', | |
382 id => $cityId, | |
383 oldView => 'city', | |
384 ]); | |
385 | |
386 my $content; | |
387 gunzip \$res->content => \$content | |
388 or die "gunzip failed: $GunzipError\n"; | |
389 | |
390 my $html = HTML::TagParser->new($content); | |
391 my @elems; | |
392 | |
393 my ($elem) = $html->getElementsByAttribute("id", "value_gold"); | |
394 $self->{'cities'}->{$cityId}->{resources}->{gold} = $elem->innerText(); | |
395 $self->{'cities'}->{$cityId}->{resources}->{gold} =~ s/,//g; | |
396 | |
397 # XXX | |
398 my ($elem) = $html->getElementsByAttribute("class", "city"); | |
399 $self->{'cities'}->{$cityId}->{name} = $elem->innerText(); | |
400 | |
401 my ($elem) = $html->getElementsByAttribute("class", 'constructionSite'); | |
402 $self->{'cities'}->{$cityId}->{construction} = 0; | |
403 $self->{'cities'}->{$cityId}->{construction} = 1 if(defined($elem)); | |
404 | |
405 # check goods | |
406 foreach my $good (qw/wood wine marble crystal sulfur/) { | |
407 my ($elem) = $html->getElementsByAttribute("id", "value_" . $good); | |
408 $self->{'cities'}->{$cityId}->{resources}->{$good} = $elem->innerText(); | |
409 $self->{'cities'}->{$cityId}->{resources}->{$good} =~ s/,//g; | |
410 } | |
411 | |
412 # search locations | |
413 foreach my $i (0..14) { | |
414 my ($elem) = $html->getElementsByAttribute("id", "position" . $i); | |
415 my $building = $elem->getAttribute('class'); | |
416 if (!($building =~ /buildingGround/)) { | |
417 $self->{'cities'}->{$cityId}->{locations}[$i] = $building; | |
418 my $span = getElementsByAttribute($elem, "class", "textLabel"); | |
419 my (undef, undef, $level) = split(/ /, $span->innerText()); | |
420 $self->{'cities'}->{$cityId}->{buildings}->{$building} = $level; | |
421 } | |
422 } | |
423 | |
424 # transporters | |
425 my ($elem) = $html->getElementsByAttribute("class", 'transAvail'); | |
426 $self->{'cities'}->{$cityId}->{transporters}->{avail} = $elem->innerText(); | |
427 my ($elem) = $html->getElementsByAttribute("class", 'transSum'); | |
428 $self->{'cities'}->{$cityId}->{transporters}->{sum} = $elem->innerText(); | |
429 $self->{'cities'}->{$cityId}->{transporters}->{sum} =~ s/\(//; | |
430 $self->{'cities'}->{$cityId}->{transporters}->{sum} =~ s/\)//; | |
431 | |
432 $res = $self->{mech}->get(sprintf('http://%s/index.php?view=militaryAdvisorMilitaryMovements', $self->{server}, $cityId)); | |
433 gunzip \$res->content => \$content | |
434 or die "gunzip failed: $GunzipError\n"; | |
435 | |
436 $self->{'cities'}->{$cityId}->{force}->{attacks} = $1 if($content =~ /敵人攻擊: (\d+)/); | |
437 $self->{'cities'}->{$cityId}->{force}->{wars} = $1 if($content =~ /我方軍隊行程: (\d+)/); | |
438 # if($content =~ /更新戰鬥報告: (\d+)/); | |
439 # if($content =~ /新的戰鬥報告: (\d+)/); | |
440 | |
441 # sub checkTownHall { | |
442 $res = $self->{mech}->get(sprintf('http://%s/index.php?view=townHall&id=%d', $self->{server}, $cityId)); | |
443 gunzip \$res->content => \$content | |
444 or die "gunzip failed: $GunzipError\n"; | |
445 | |
446 # check happiness | |
447 # Happiness = Basic bonuses (196 + Capital Bonus + Holiday Bonus(25)) + | |
448 # Wine (Tavern Base(12*level) + | |
449 # Tavern Bonus(80*step)) + | |
450 # Culture (Museum Base(20*level) + | |
451 # Cultural Goods Bonus(50*Cultural Goods)) - | |
452 # Population (population) - | |
453 # Corruption (Corruption rate * population) | |
454 # | |
455 # Growth Rate = Happiness * 0.02 | |
456 $html = HTML::TagParser->new($content); | |
457 | |
458 my @happiness = ("ecstatic", "happy", "neutral", "sad", "outraged"); | |
459 foreach my $j (0..$#happiness) { | |
460 my ($elem) = $html->getElementsByAttribute("class", sprintf("happiness happiness_%s", $happiness[$j])); | |
461 if(defined($elem)) { | |
462 $self->{'cities'}->{$cityId}->{happiness} = $j; | |
463 $self->{'cities'}->{$cityId}->{happiness_text} = $happiness[$j]; | |
464 } | |
465 } | |
466 | |
467 # Space, 房屋數 | |
468 $self->{'cities'}->{$cityId}->{"space"} = {}; | |
469 foreach my $j (qw/occupied total/) { | |
470 my ($elem) = $html->getElementsByAttribute("class", sprintf("value %s", $j)); | |
471 if(defined($elem)) { | |
472 $self->{'cities'}->{$cityId}->{"space"}->{$j} = $elem->innerText(); | |
473 } | |
474 } | |
475 | |
476 # Actions | |
477 # <span id="value_maxActionPoints">1</span> | |
478 | |
479 # <li class="incomegold incomegold_negative"> | |
480 # <li class="incomegold incomegold_positive"> | |
481 # <span class="value">-178</span> | |
482 | |
483 my ($elem) = $html->getElementsByAttribute("title", "目前腐敗程度"); | |
484 if(defined($elem)) { | |
485 $self->{'cities'}->{$cityId}->{corruption} = $elem->innerText(); | |
486 $self->{'cities'}->{$cityId}->{corruption} =~ s/%//g; | |
487 } | |
488 | |
489 # countCiizens | |
490 my @citizens_type = qw/citizens woodworkers specialworkers scientists/; | |
491 @elems = $html->getElementsByAttribute('class', 'count'); | |
492 $self->{'cities'}->{$cityId}->{'citizens'} = {}; | |
493 $self->{'cities'}->{$cityId}->{'citizens'}->{total} = 0; | |
494 | |
495 foreach my $i (0..$#citizens_type) | |
496 { | |
497 $self->{'cities'}->{$cityId}->{'citizens'}->{$citizens_type[$i]} = $elems[$i]->innerText(); | |
498 $self->{'cities'}->{$cityId}->{'citizens'}->{total} += $elems[$i]->innerText();; | |
499 } | |
500 | |
501 # } | |
502 | |
503 $self->{'cities'}->{$cityId}->{'research'} = $self->checkResearch($cityId); | 603 $self->{'cities'}->{$cityId}->{'research'} = $self->checkResearch($cityId); |
504 | 604 } |
505 # sub checkArmies { | 605 print Dumper($self->{'cities'}); |
506 my %force_types; | |
507 $force_types{'army'} = [ qw/undef undef Slinger Swordsman Phalanx Ram Archer Catapult Gunsman Mortar SteamGiant Gyrocopter Bombardier Doctor Cook/ ]; | |
508 $force_types{'fleet'} = [ qw/undef undef Ram-Ship BallistaShip Flamethrower CatapultShip MortarShip PaddleWheelRam DivingBoat/ ]; | |
509 foreach my $x (qw/army fleet/) | |
510 { | |
511 $self->{'cities'}->{$cityId}->{$x} = {}; | |
512 # search army | |
513 $res = $self->{mech}->get(sprintf('http://%s/index.php?view=cityMilitary-%s&id=%d', $self->{server}, $x, $cityId)); | |
514 gunzip \$res->content => \$content | |
515 or die "gunzip failed: $GunzipError\n"; | |
516 | |
517 $html = HTML::TagParser->new($content); | |
518 @elems = $html->getElementsByTagName('td'); | |
519 foreach my $j (0..$#{$force_types{$x}}) { | |
520 next if($force_types{$x}[$j] eq 'undef'); | |
521 if($elems[$j]->innerText() == '-') { | |
522 $self->{'cities'}->{$cityId}->{$x}->{$force_types{$x}[$j]} = 0; | |
523 } else { | |
524 $self->{'cities'}->{$cityId}->{$x}->{$force_types{$x}[$j]} = $elems[$j]->innerText(); | |
525 } | |
526 } | |
527 } | |
528 } | |
529 # print Dumper($self->{'cities'}); | |
530 return $self->{'cities'}; | 606 return $self->{'cities'}; |
531 } | 607 } |
532 | 608 |
533 sub logout | 609 sub logout |
534 { | 610 { |
542 | 618 |
543 my $res = $self->{mech}->post(sprintf("http://%s/index.php?action=loginAvatar&function=login", $self->{server}), [ | 619 my $res = $self->{mech}->post(sprintf("http://%s/index.php?action=loginAvatar&function=login", $self->{server}), [ |
544 name => $self->{user}, | 620 name => $self->{user}, |
545 password => $self->{pass}, | 621 password => $self->{pass}, |
546 ]); | 622 ]); |
623 | |
547 my $c; | 624 my $c; |
548 my $status = gunzip \$res->content => \$c | 625 my $status = gunzip \$res->content => \$c |
549 or die "gunzip failed: $GunzipError\n"; | 626 or die "gunzip failed: $GunzipError\n"; |
550 | 627 |
551 if($c =~ /錯誤!/) | 628 if($c =~ /錯誤!/) |
552 { | 629 { |
553 die ("password error\n"); | 630 die ("password error\n"); |
554 } else { | 631 } else { |
555 my $html = HTML::TagParser->new($c); | 632 my $result = XML::LibXML->new('1.0','utf-8') |
556 my @elems; | 633 ->parse_html_string ($c, { suppress_errors => 1 }) |
557 | 634 ->find( '//option[@class="avatarCities coords"]' ); |
558 # XXX | 635 |
559 @elems = $html->getElementsByAttribute("class", "avatarCities coords"); | 636 if ( $result->isa( 'XML::LibXML::NodeList' ) ) { |
560 foreach my $elem (@elems) { | 637 foreach ( @$result ) { |
561 # my cities | 638 $self->{'cities'}->{$_->getAttribute('value')} = {}; |
562 $self->{'cities'}->{$elem->getAttribute('value')} = {}; | 639 } |
563 } | 640 } |
564 } | 641 } |
565 } | 642 } |
566 | 643 |
567 sub getElementsByTagName { | 644 sub getElementsByTagName { |