File Coverage

blib/lib/Chess/Games/DotCom.pm
Criterion Covered Total %
statement 21 75 28.0
branch 0 10 0.0
condition 0 7 0.0
subroutine 7 12 58.3
pod 2 3 66.6
total 30 107 28.0


line stmt bran cond sub pod time code
1             package Chess::Games::DotCom;
2              
3 1     1   35311 use 5.006001;
  1         6  
  1         48  
4 1     1   8 use strict;
  1         2  
  1         45  
5 1     1   5 use warnings;
  1         5  
  1         38  
6              
7 1     1   129369 use Data::Dumper;
  1         28491  
  1         108  
8 1     1   2538 use HTML::Entities;
  1         33087  
  1         120  
9 1     1   1386 use HTML::TreeBuilder;
  1         30864  
  1         17  
10 1     1   996 use LWP::Simple;
  1         1064582  
  1         13  
11              
12             require Exporter;
13              
14             our @ISA = qw(Exporter);
15              
16             # Items to export into callers namespace by default. Note: do not export
17             # names by default without a very good reason. Use EXPORT_OK instead.
18             # Do not simply export all your public functions/methods/constants.
19              
20             # This allows declaration use Chess::Games::DotCom ':all';
21             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
22             # will save memory.
23             our %EXPORT_TAGS = ( 'all' => [ qw(
24            
25             ) ] );
26              
27             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
28              
29             our @EXPORT = qw(
30             game_of_day puzzle_of_day
31             );
32              
33             our $VERSION = '1.2';
34              
35             our $home = 'http://www.chessgames.com';
36             my $tb = HTML::TreeBuilder->new;
37              
38             # Preloaded methods go here.
39              
40             my $ua;
41              
42             sub _init_ua
43             {
44 0     0     require LWP;
45 0           require LWP::UserAgent;
46 0           require HTTP::Status;
47 0           require HTTP::Date;
48 0           $ua = new LWP::UserAgent; # we create a global UserAgent object
49 0           my $ver = $LWP::VERSION = $LWP::VERSION; # avoid warning
50 0           $ua->agent("Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101");
51 0           $ua->env_proxy;
52             }
53              
54            
55             sub _get
56             {
57 0     0     my $url = shift;
58 0           my $ret;
59              
60 0 0         _init_ua() unless $ua;
61 0 0 0       if (@_ && $url !~ /^\w+:/)
62             {
63             # non-absolute redirect from &_trivial_http_get
64 0           my($host, $port, $path) = @_;
65 0           require URI;
66 0           $url = URI->new_abs($url, "http://$host:$port$path");
67             }
68 0           my $request = HTTP::Request->new
69             (GET => $url,
70            
71             );
72 0           my $response = $ua->request($request);
73 0 0         return $response->is_success ? $response->content : undef;
74             }
75              
76             sub pgn_url {
77              
78 0     0 0   my $gid = shift;
79              
80 0           "http://www.chessgames.com/perl/nph-chesspgndownload?gid=$gid"
81             }
82              
83             sub game_of_day {
84              
85 0   0 0 1   my $outfile = shift || "game_of_day.pgn";
86              
87             # retrieve http://www.chessgames.com
88              
89 0           my $html = get $home;
90              
91             # parse the page
92              
93 0           $tb->parse($html);
94              
95 0           my $god; # god == Game of the Day
96              
97             # make it so that text nodes are changed into nodes with tags
98             # just like any other HTML aspect.
99             # then they can be searched with look_down
100 0           $tb->objectify_text;
101              
102             # Find the place in the HTML where Game of the Day is
103 0           my $G = $tb->look_down
104             (
105             '_tag' => '~text',
106             text => 'Game of the Day'
107             );
108              
109 0           my $table = $G->look_up
110             (
111             '_tag' => 'table',
112             );
113              
114 0           my @tr = $table->look_down('_tag' => 'tr');
115              
116 0           my $god_tr = $tr[1];
117              
118 0           my $a = $god_tr->look_down('_tag' => 'a');
119              
120             # lets get the URL of the game
121 0           my $game_url = $a->attr('href');
122 0           my ($game_id) = $game_url =~ m/(\d+)/;
123              
124             # let's get the game, faking out the web spider filter in the process:
125 0           my $pgn = _get pgn_url $game_id;
126              
127             # let's save it to disk
128 0 0         open F, ">$outfile" or die "error opening $outfile for writing: $!";
129 0           print F $pgn;
130 0           close(F)
131             }
132              
133             sub puzzle_of_day {
134              
135 0   0 0 1   my $outfile = shift || "puzzle_of_day.pgn";
136              
137             # warn $outfile;
138              
139              
140             # retrieve http://www.chessgames.com
141              
142 0           my $html = get $home;
143              
144             # parse the page
145              
146 0           $tb->parse($html);
147              
148 0           my $pod; # god == Game of the Day
149              
150             # make it so that text nodes are changed into nodes with tags
151             # just like any other HTML aspect.
152             # then they can be searched with look_down
153 0           $tb->objectify_text;
154              
155             # Find the place in the HTML where Game of the Day is
156 0           my $G = $tb->look_down
157             (
158             '_tag' => '~text',
159             text => 'See game for solution.'
160             );
161              
162             # warn $G->as_HTML;
163              
164             # find _all_ tr in the lineage of the found node... I don't know a
165             # way to limit the search
166 0           my $table = $G->look_up
167             (
168             '_tag' => 'table',
169             );
170              
171              
172 0           my $winner = $table->look_down
173             (
174             '_tag' => '~text',
175             'text' => qr/^\d+/
176             );
177            
178              
179 0           my $winner_content = $winner->attr('text');
180              
181 0           decode_entities($winner_content);
182              
183             # die $winner_content;
184              
185 0           my $A = $table->look_down
186             (
187             '_tag' => 'a',
188             );
189              
190              
191             # $A->dump;
192              
193 0           my $game_url = $A->attr('href');
194              
195 0           my ($game_id) = $game_url =~ m/(\d+)/;
196            
197              
198             # let's get the game, faking out the web spider filter in the process:
199 0           my $pgn = _get pgn_url $game_id;
200              
201 0           $pgn =~ s!PlyCount.+\]!PlyCount \"$winner_content\"\]!;
202              
203             # die $pgn;
204              
205             # let's save it to disk
206 0 0         open F, ">$outfile" or die "error opening $outfile for writing: $!";
207 0           print F $pgn;
208 0           close(F)
209            
210             }
211              
212             1;
213             __END__
214             # Below is stub documentation for your module. You'd better edit it!
215              
216             =head1 NAME
217              
218             Chess::Games::DotCom - API for accessing chessgames.com
219              
220             =head1 SYNOPSIS
221              
222             shell> perl -MChess::Games::DotCom -e game_of_day
223             shell> perl -MChess::Games::DotCom -e 'game_of_day("myfile.pgn")'
224              
225             shell> perl -MChess::Games::DotCom -e puzzle_of_day
226             shell> perl -MChess::Games::DotCom -e 'puzzle_of_day("myfile.pgn")'
227              
228             =head1 ABSTRACT
229              
230             Download games from chessgames.com.
231              
232             A script in scripts suitable for invocation from cron is included.
233              
234             =head1 API
235              
236             =head2 game_of_day [ $filename ]
237              
238             Downloads the game of the day. If C<$filename> is not specified, then
239             it downloads it to C<game_of_day.pgn>.
240              
241             =head2 puzzle_of_day [ $filename ]
242              
243             Downloads the puzzle of the day. If C<$filename> is not specified, then
244             it downloads it to C<puzzle_of_day.pgn>.
245              
246             =head2 EXPORT
247              
248             C<game_of_day>
249             C<puzzle_of_day>
250              
251             =head1 NEW FEATURES
252              
253             =head2 in 0.09
254              
255             Realized that I parsed out the wrong thing and parsed out something like:
256              
257             12. ...?
258              
259             instead.
260              
261             Stored this in plycount instead.
262              
263             =head2 in 0.08
264              
265             For C<puzzle_of_day()>,
266             parsed out "$color to move and win" and stored in the PlyCount header of
267             PGN so that I could see where the puzzle began.
268              
269             Too see an example of a log of auto-downloaded games, visit:
270              
271             http://princepawn.perlmonk.org/chess/pgn/montreux.html
272              
273             =head2 in 0.07
274              
275             Added a sample cron file for daily automatic retrieval of puzzle of day.
276              
277             Added Log::Agent logging to sample retrieval script
278              
279             =head2 in 0.06
280              
281             C<puzzle_of_day> was added
282              
283              
284             =head1 TODO
285              
286             Download other daily game parts of the site
287              
288             =head1 RESOURCES
289              
290             The Perl Chess Mailing List:
291              
292             http://www.yahoogroups.com/group/perl-chess
293              
294             =head1 AUTHOR
295              
296             T. M. Brannon, <tbone@cpan.org>
297              
298              
299             =head1 INSTALLATION
300              
301             You must have the following installed:
302              
303             =over 4
304              
305             =item 1 URI
306              
307             =item 2 Bundle::LWP
308              
309             =item 3 HTML::Tree
310              
311             =back
312              
313             =head2 Optional
314              
315             For the script in the C<scripts> directory, you also need:
316              
317             =over 4
318              
319             =item 4 File::Butler
320              
321             =item 5 File::Temp
322              
323             =item 6 Log::Agent
324              
325             =cut
326              
327             =head1 COPYRIGHT AND LICENSE
328              
329             Copyright 2003 by T. M. Brannon
330              
331             This library is free software; you can redistribute it and/or modify
332             it under the same terms as Perl itself.
333              
334             =cut