File Coverage

blib/lib/Net/AozoraBunko.pm
Criterion Covered Total %
statement 37 150 24.6
branch 3 36 8.3
condition 4 5 80.0
subroutine 11 26 42.3
pod 10 10 100.0
total 65 227 28.6


!);
line stmt bran cond sub pod time code
1             package Net::AozoraBunko;
2 3     3   647720 use strict;
  3         8  
  3         108  
3 3     3   18 use warnings;
  3         7  
  3         85  
4 3     3   971 use utf8;
  3         19  
  3         17  
5 3     3   102 use Carp qw/croak/;
  3         6  
  3         220  
6              
7 3     3   22471 use URI;
  3         27580  
  3         95  
8 3     3   2922 use URI::Fetch;
  3         441765  
  3         124  
9 3     3   26 use LWP::UserAgent;
  3         8  
  3         69  
10 3     3   1979 use Encode qw/decode/;
  3         23511  
  3         325  
11 3     3   2712 use Web::Scraper;
  3         409893  
  3         28  
12              
13             our $VERSION = '0.05';
14              
15             my $DOMAIN = 'http://www.aozora.gr.jp';
16             my $PAGES = {
17             author_base_regex => qr!^\Q$DOMAIN\E/index_pages/!,
18             text_base_regex => qr!^\Q$DOMAIN\E/cards/\d+/.+\.(?:html|zip)$!,
19             authors_index => "$DOMAIN/index_pages/person_all_all.html",
20             author_detail => "$DOMAIN/index_pages",
21             };
22              
23             my $ENCODE = {
24             html => 'utf8',
25             text => 'cp932',
26             };
27              
28             my $UA = LWP::UserAgent->new(
29             agent => __PACKAGE__ . '/' . $VERSION,
30             timeout => 10,
31             );
32              
33             sub new {
34 2     2 1 2134 my $class = shift;
35 2   100     13 my $args = shift || +{};
36              
37 2         8 my $self = bless $args, $class;
38              
39 2   66     24 $self->ua($args->{ua} || $UA);
40              
41 2         6 return $self;
42             }
43              
44             sub search_author {
45 0     0 1 0 my $self = shift;
46 0         0 my $keyword = shift; # utf8 flagged
47              
48 0 0       0 return [] unless $keyword;
49              
50 0         0 my $authors = $self->authors;
51              
52 0         0 my @result;
53 0         0 for my $r (@{$authors}) {
  0         0  
54 0 0       0 if ($r->{name} =~ m!\Q$keyword\E!) {
55 0         0 push @result, $r;
56             }
57             }
58              
59 0         0 return \@result;
60             }
61              
62             sub search_work {
63 0     0 1 0 my $self = shift;
64 0         0 my $author_page = shift; # URL or ID(*** = /person***.html)
65 0         0 my $keyword = shift; # utf8 flagged
66              
67 0 0       0 return [] unless $author_page;
68 0 0       0 return [] unless $keyword;
69              
70 0 0       0 if ($author_page =~ m!^\d+$!) {
71 0         0 return $self->search_work(
72             "$PAGES->{author_detail}/person$author_page.html",
73             $keyword
74             );
75             }
76              
77 0         0 my $writings = $self->all_works($author_page);
78              
79 0         0 my @result;
80 0         0 for my $r (@{$writings}) {
  0         0  
81 0 0       0 if ($r->{title} =~ m!\Q$keyword\E!) {
82 0         0 push @result, $r;
83             }
84             }
85              
86 0         0 return \@result;
87             }
88              
89             sub authors {
90 0     0 1 0 my $self = shift;
91              
92             my $authors = scraper {
93             process 'li', 'authors[]' => scraper {
94 0         0 process 'a', name => 'TEXT', url => '@href';
95 0     0   0 };
96 0         0 };
97              
98 0         0 my $uri = URI->new($PAGES->{authors_index});
99              
100 0         0 my $res = $authors->scrape($self->_fetch($uri, $ENCODE->{html}), $uri);
101              
102 0         0 return $res->{authors};
103             }
104              
105             sub author {
106 0     0 1 0 my $self = shift;
107 0         0 my $uri = shift;
108              
109 0         0 $self->_check_uri(\$uri);
110              
111             my $author = scraper {
112             process 'table>tr', 'data[]' => sub {
113 0         0 my $line = $_->as_HTML;
114 0         0 my ($key, $value) = map {
115 0         0 my $html = $_;
116 0         0 $html =~ s/<[^>]+>//g;
117 0         0 $html;
118             } ($line =~ m!]+>(.+)(.+)
119 0         0 return { $key => $value };
120 0     0   0 };
121 0         0 };
122              
123 0         0 my $data = $author->scrape(
124             $self->_fetch($uri, $ENCODE->{html}), $uri
125             )->{data};
126              
127 0         0 my $person;
128 0         0 for my $dat (@{$data}) {
  0         0  
129 0         0 my @keys = keys %{$dat};
  0         0  
130 0         0 $person->{$keys[0]} = $dat->{$keys[0]};
131             }
132              
133 0         0 return $person;
134             }
135              
136             sub works {
137 0     0 1 0 my $self = shift;
138 0         0 return $self->_get_works($_[0]);
139             }
140              
141             sub all_works {
142 0     0 1 0 my $self = shift;
143 0         0 return $self->_get_works($_[0], 1);
144             }
145              
146             sub _get_works {
147 0     0   0 my $self = shift;
148 0         0 my $uri = shift;
149 0         0 my $all = shift;
150              
151 0         0 $self->_check_uri(\$uri);
152              
153             my $list = scraper {
154 0     0   0 process 'li', 'list[]' => 'RAW';
155 0         0 };
156              
157 0         0 my $works = $list->scrape($self->_fetch($uri, $ENCODE->{html}), $uri);
158              
159 0         0 my $writings = [];
160 0 0       0 if (ref $works->{list} eq 'ARRAY') {
161 0         0 for my $work (@{$works->{list}}) {
  0         0  
162 0         0 my $title = '';
163 0         0 my $url = '';
164 0 0       0 if ($work =~ /^
    0          
165 0         0 ($url, $title) = ($work =~ m!([^<]+)!);
166 0         0 $url = URI->new_abs($url, $uri);
167             }
168             elsif ($all) {
169 0         0 ($title, undef) = split / (/, $work;
170             }
171             else {
172 0         0 next;
173             }
174 0         0 push @{$writings}, { title => $title, url => $url, };
  0         0  
175             }
176             }
177              
178 0         0 return $writings;
179             }
180              
181             sub get_text {
182 0     0 1 0 my $self = shift;
183 0         0 my $uri = shift;
184              
185 0         0 my $zip = $self->_zip_uri($uri);
186              
187 0         0 require IO::Uncompress::Unzip;
188 0         0 require IO::String;
189              
190 0         0 IO::Uncompress::Unzip::unzip(
191             IO::String->new($zip) => my $out = IO::String->new
192             );
193 0         0 my $text = decode($ENCODE->{text}, ${$out->string_ref});
  0         0  
194              
195 0         0 return $text;
196             }
197              
198             sub get_zip {
199 0     0 1 0 my $self = shift;
200 0         0 my $uri = shift;
201              
202 0         0 my $zip = $self->_zip_uri($uri);
203              
204 0         0 return $zip;
205             }
206              
207             sub _zip_uri {
208 0     0   0 my $self = shift;
209 0         0 my $uri = shift;
210              
211 0 0       0 croak 'uri is blank' unless $uri;
212              
213 0 0       0 unless ($uri =~ /$PAGES->{text_base_regex}/) {
214 0         0 croak "wrong uri: $uri";
215             }
216              
217 0 0       0 if ($uri =~ /\.html$/) {
218 0         0 my $html = $self->_fetch($uri, $ENCODE->{html});
219 0         0 my ($zip_path) = ($html =~ m!.+\.zip!);
220 0         0 my $zip_uri = URI->new_abs($zip_path, $uri);
221 0         0 return $self->_zip_uri($zip_uri);
222             }
223              
224 0         0 my $zip = $self->_fetch($uri);
225              
226 0         0 return $zip;
227             }
228              
229             sub ua {
230 7     7 1 1324 my $self = shift;
231 7         10 my $ua = shift;
232              
233 7 100       19 if ($ua) {
234 3 50       20 $self->{ua} = $ua if ref $ua eq 'LWP::UserAgent';
235             }
236             else {
237 4         26 return $self->{ua};
238             }
239             }
240              
241             sub _fetch {
242 0     0     my $self = shift;
243 0           my $uri = shift;
244 0           my $char = shift;
245              
246 0 0         my $fetch_response = URI::Fetch->fetch(
247             $uri,
248             UserAgent => $self->ua,
249             ) or croak "could not fetch [$uri]: $!";
250              
251 0 0         if ($char) {
252 0           return decode($char, $fetch_response->content);
253             }
254             else {
255 0           return $fetch_response->content;
256             }
257             }
258              
259             sub _check_uri {
260 0     0     my $self = shift;
261 0           my $uri = shift;
262              
263 0 0         croak 'uri is blank' unless $$uri;
264              
265 0 0         unless ($$uri =~ m!$PAGES->{author_base_regex}!) {
266 0           croak "not author's URL: $$uri";
267             }
268             else {
269 0           $$uri = URI->new($$uri);
270             }
271             }
272              
273             1;
274              
275             __END__