File Coverage

blib/lib/WWW/Scraper/ISBN/Booktopia_Driver.pm
Criterion Covered Total %
statement 75 80 93.7
branch 16 36 44.4
condition 8 18 44.4
subroutine 7 7 100.0
pod 1 1 100.0
total 107 142 75.3


line stmt bran cond sub pod time code
1             package WWW::Scraper::ISBN::Booktopia_Driver;
2              
3 6     6   106753 use strict;
  6         12  
  6         201  
4 6     6   24 use warnings;
  6         7  
  6         183  
5              
6 6     6   24 use vars qw($VERSION @ISA);
  6         12  
  6         440  
7             $VERSION = '0.21';
8              
9             #--------------------------------------------------------------------------
10              
11             =head1 NAME
12              
13             WWW::Scraper::ISBN::Booktopia_Driver - Search driver for Booktopia online book catalog.
14              
15             =head1 SYNOPSIS
16              
17             See parent class documentation (L)
18              
19             =head1 DESCRIPTION
20              
21             Searches for book information from Booktopia online book catalog
22              
23             =cut
24              
25             #--------------------------------------------------------------------------
26              
27             ###########################################################################
28             # Inheritence
29              
30 6     6   25 use base qw(WWW::Scraper::ISBN::Driver);
  6         8  
  6         2867  
31              
32             ###########################################################################
33             # Modules
34              
35 6     6   9034 use WWW::Mechanize;
  6         731492  
  6         277  
36              
37             ###########################################################################
38             # Constants
39              
40 6     6   48 use constant SEARCH => 'http://www.booktopia.com.au/search.ep?cID=&submit.x=44&submit.y=7&submit=search&keywords=';
  6         8  
  6         6248  
41             my ($BAU_URL1,$BAU_URL2,$BAU_URL3) = ('http://www.booktopia.com.au','/[^/]+/prod','.html');
42              
43             #--------------------------------------------------------------------------
44              
45             ###########################################################################
46             # Public Interface
47              
48             =head1 METHODS
49              
50             =over 4
51              
52             =item C
53              
54             Creates a query string, then passes the appropriate form fields to the
55             Booktopia server.
56              
57             The returned page should be the correct catalog page for that ISBN. If not the
58             function returns zero and allows the next driver in the chain to have a go. If
59             a valid page is returned, the following fields are returned via the book hash:
60              
61             isbn (now returns isbn13)
62             isbn10
63             isbn13
64             ean13 (industry name)
65             author
66             title
67             book_link
68             image_link
69             description
70             pubdate
71             publisher
72             binding (if known)
73             pages (if known)
74             weight (if known) (in grammes)
75             width (if known) (in millimetres)
76             height (if known) (in millimetres)
77             depth (if known) (in millimetres)
78              
79             The book_link and image_link refer back to the Booktopia website.
80              
81             =back
82              
83             =cut
84              
85             sub search {
86 3     3 1 18258 my $self = shift;
87 3         8 my $isbn = shift;
88 3         12 $self->found(0);
89 3         37 $self->book(undef);
90              
91             # validate and convert into EAN13 format
92 3         24 my $ean = $self->convert_to_ean13($isbn);
93 3 50 66     117 return $self->handler("Invalid ISBN specified [$isbn]")
      33        
      66        
      33        
94             if(!$ean || (length $isbn == 13 && $isbn ne $ean)
95             || (length $isbn == 10 && $isbn ne $self->convert_to_isbn10($ean)));
96              
97             #print STDERR "\n# isbn=[$isbn] => ean=[$ean]\n";
98 3         34 $isbn = $ean;
99              
100 3         20 my $mech = WWW::Mechanize->new();
101 3         17034 $mech->agent_alias( 'Linux Mozilla' );
102              
103             #print STDERR "\n# url=[".(SEARCH . $isbn)."]\n";
104              
105 3         171 eval { $mech->get( SEARCH . $isbn ) };
  3         15  
106 3 50 33     7319490 return $self->handler("Booktopia website appears to be unavailable.")
      33        
107             if($@ || !$mech->success() || !$mech->content());
108              
109 3         157 my $pattern = $isbn;
110 3 50       12 if(length $isbn == 10) {
111 0         0 $pattern = '978' . $isbn;
112 0         0 $pattern =~ s/.$/./;
113             }
114              
115             # The Book page
116 3         7 my $html = $mech->content();
117              
118 3 50       6952 return $self->handler("Failed to find that book on Booktopia website. [$isbn]")
119             if($html =~ m!Sorry, we couldn't find any matches for!si);
120            
121             #print STDERR "\n# html=[\n$html\n]\n";
122              
123 3         6 my $data;
124 3         4210 ($data->{publisher}) = $html =~ m!\s*Publisher:\s*\s*([^<]+)!si;
125 3         3572 ($data->{pubdate}) = $html =~ m!\s*Published:\s*\s*([^<]+)!si;
126              
127 3 50       24 $data->{publisher} =~ s!<[^>]+>!!g if($data->{publisher});
128 3 50       29 $data->{pubdate} =~ s!\s+! !g if($data->{pubdate});
129              
130 3         4110 ($data->{image}) = $html =~ m!(http://covers.booktopia.com.au/big/\d+/[-\w]+\.jpg)!si;
131 3         1321 ($data->{thumb}) = $html =~ m!(http://covers.booktopia.com.au/\d+/\d+/[-\w]+\.jpg)!si;
132 3         4023 ($data->{isbn13}) = $html =~ m!\s*ISBN:\s*\s*(\d+)!si;
133 3         4021 ($data->{isbn10}) = $html =~ m!\s*ISBN-10:\s*\s*(\d+)!si;
134 3         3995 ($data->{author}) = $html =~ m!
\s*(?:By|Author):\s*(.*?)
!si;
135 3         1810 ($data->{title}) = $html =~ m!
136 3 50       18 ($data->{title}) = $html =~ m!([^<]+)

!si unless($data->{title});
137 3         4253 ($data->{description}) = $html =~ m!
(.*?)
!si;
138 3         4167 ($data->{binding}) = $html =~ m!\s*Format:\s*\s*([^<]+)!si;
139 3         4080 ($data->{pages}) = $html =~ m!\s*Number Of Pages:\s*\s*([\d.]+)!si;
140 3         4173 ($data->{weight}) = $html =~ m!\s*Weight \(kg\):\s*\s*([\d.]+)!si;
141 3         4082 ($data->{height},$data->{width},$data->{depth})
142             = $html =~ m!\s*Dimensions \(cm\):\s*([\d.]+)\s* x \s*([\d.]+)\s* x \s*([\d.]+)!si;
143              
144             # despite it saying Kg (kilogrammes) the weight seems to vary between widely!
145 3 50       17 if($data->{weight}) {
146 3 50       25 if( $data->{weight} < 1) {$data->{weight} = int($data->{weight} * 1000)}
  3 0       17  
  0 0       0  
147 0         0 elsif($data->{weight} < 100) {$data->{weight} = int($data->{weight} * 10)}
148 0         0 elsif($data->{weight} < 1000) {$data->{weight} = int($data->{weight})}
149             else {$data->{weight} = int($data->{weight})}
150             }
151            
152 3 50       17 $data->{height} = int($data->{height} * 10) if($data->{height});
153 3 50       19 $data->{width} = int($data->{width} * 10) if($data->{width});
154 3 50       44 $data->{depth} = int($data->{depth} * 10) if($data->{depth});
155              
156 3 50       26 if($data->{author}) {
157 3         34 $data->{author} =~ s!!,!g;
158 3         25 $data->{author} =~ s!<[^>]+>!!g;
159 3         21 $data->{author} =~ s!\s*,\s*!, !g;
160 3         21 $data->{author} =~ s!\s*,\s*$!!g;
161             }
162              
163 3 50       11 if($data->{description}) {
164 3         42 $data->{description} =~ s!Click on the Google Preview[^<]+!!s;
165 3         259 $data->{description} =~ s!!\n!gi;
166 3         87 $data->{description} =~ s!<[^>]+>!!g;
167             }
168              
169             #use Data::Dumper;
170             #print STDERR "\n# " . Dumper($data);
171              
172 3 50       11 return $self->handler("Could not extract data from Booktopia result page.")
173             unless(defined $data);
174              
175             # trim top and tail
176 3 50       24 foreach (keys %$data) { next unless(defined $data->{$_});$data->{$_} =~ s/^\s+//;$data->{$_} =~ s/\s+$//; }
  45         67  
  45         87  
  45         224  
177              
178 3         36 my $bk = {
179             'ean13' => $data->{isbn13},
180             'isbn13' => $data->{isbn13},
181             'isbn10' => $data->{isbn10},
182             'isbn' => $data->{isbn13},
183             'author' => $data->{author},
184             'title' => $data->{title},
185             'book_link' => $mech->uri(),
186             'image_link' => $data->{image},
187             'thumb_link' => $data->{thumb},
188             'description' => $data->{description},
189             'pubdate' => $data->{pubdate},
190             'publisher' => $data->{publisher},
191             'binding' => $data->{binding},
192             'pages' => $data->{pages},
193             'weight' => $data->{weight},
194             'width' => $data->{width},
195             'height' => $data->{height},
196             'depth' => $data->{depth},
197             'html' => $html
198             };
199              
200             #use Data::Dumper;
201             #print STDERR "\n# book=".Dumper($bk);
202              
203 3         153 $self->book($bk);
204 3         45 $self->found(1);
205 3         24 return $self->book;
206             }
207              
208             1;
209              
210             __END__