File Coverage

blib/lib/WWW/Scraper/Lite.pm
Criterion Covered Total %
statement 76 80 95.0
branch 16 20 80.0
condition n/a
subroutine 13 13 100.0
pod 8 8 100.0
total 113 121 93.3


line stmt bran cond sub pod time code
1             # -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
2             # vim:ts=8:sw=2:et:sta:sts=2
3             #########
4             # Author: rmp
5             # Last Modified: $Date: 2011-06-02 22:46:31 +0100 (Thu, 02 Jun 2011) $
6             # Id: $Id: Lite.pm 15 2011-06-02 21:46:31Z rmp $
7             # Source: $Source$
8             # $HeadURL: svn+ssh://psyphi.net/repository/svn/www-scraper-lite/trunk/lib/WWW/Scraper/Lite.pm $
9             #
10             package WWW::Scraper::Lite;
11 2     2   10071 use strict;
  2         5  
  2         78  
12 2     2   12 use warnings;
  2         3  
  2         63  
13 2     2   2370 use LWP::UserAgent;
  2         118697  
  2         74  
14 2     2   2120 use HTML::TreeBuilder::XPath;
  2         295120  
  2         27  
15 2     2   67 use Carp;
  2         3  
  2         1572  
16              
17             our $VERSION = do { my ($r) = q$Revision: 15 $ =~ /(\d+)/smx; $r; };
18              
19             sub new {
20 6     6 1 3158 my ($class, $ref) = @_;
21 6 100       19 if(!$ref) {
22 4         7 $ref = {};
23             }
24              
25 6         12 bless $ref, $class;
26              
27 6         15 $ref->{queue} = [];
28 6         11 $ref->{seen} = {};
29              
30 6         14 return $ref;
31             }
32              
33             sub ua {
34 3     3 1 451 my $self = shift;
35              
36 3 100       15 if(!$self->{ua}) {
37 1         8 $self->{ua} = LWP::UserAgent->new();
38             }
39              
40 3         2833 return $self->{ua};
41             }
42              
43             sub crawl {
44 1     1 1 8 my ($self, $url_in, $callbacks) = @_;
45              
46 1         4 $self->enqueue($url_in);
47              
48 1         3 while(my $url = $self->dequeue()) {
49 1         3 $self->{current} = {};
50 1         1 my $current = $self->{current};
51              
52 1 50       5 if($self->{seen}->{$url}++) {
53             #########
54             # already fetched $url
55             #
56 0         0 next;
57             }
58              
59 1         2 $current->{url} = $url;
60 1         4 my $res = $self->ua->get($url);
61 1         11 $current->{response} = $res;
62              
63 1         16 my $tree = HTML::TreeBuilder::XPath->new;
64 1         336 $tree->parse_content($res->content);
65              
66 1         381 while(my ($pattern, $cb) = each %{$callbacks}) {
  2         30  
67 1         9 my $nb = $tree->findnodes($pattern);
68 1         1894 for my $node (@{$nb}) {
  1         3  
69 1         4 $cb->($self, $node);
70             }
71             }
72              
73             #########
74             # now the recommended cleanup
75             #
76 1         7 $tree->delete;
77             }
78 1         5 return 1;
79             }
80              
81             sub enqueue {
82 2     2 1 8 my ($self, @urls) = @_;
83 2         4 push @{$self->{queue}}, grep { defined } @urls;
  2         4  
  3         7  
84 2         8 return 1;
85             }
86              
87             sub dequeue {
88 3     3 1 77 my $self = shift;
89 3         6 my $url = shift @{$self->{queue}};
  3         6  
90 3         11 return $url;
91             }
92              
93             sub current {
94 3     3 1 3 my $self = shift;
95 3         6 return $self->{current};
96             }
97              
98             sub url_remove_anchor {
99 2     2 1 6 my ($self, $url) = @_;
100 2 100       10 if(!$url) {
101 1         5 return;
102             }
103              
104 1         5 $url =~ s{[#].*}{}smx;
105 1         4 return $url;
106             }
107              
108             sub url_make_absolute {
109 4     4 1 11 my ($self, $url) = @_;
110              
111 4 100       11 if(!$url) {
112 1         4 return q[];
113             }
114              
115 3         6 my $current = $self->current;
116 3         5 my $current_url = $current->{url};
117 3 50       7 if(!$current_url) {
118 0         0 return;
119             }
120 3         13 my ($current_domain) = $current_url =~ m{^([[:lower:]]+://[^/]+)}smix;
121 3         8 my ($current_dir) = $current_url =~ m{^([[:lower:]]+://.*/)}smix;
122              
123 3 50       7 if(!$current_dir) {
124 0         0 $current_dir = q[/];
125             }
126              
127 3 50       22 if($url =~ m{^mailto:}smix) {
128 0         0 return $url;
129             }
130              
131 3 100       10 if($url =~ m{^[[:lower:]]+://}smix) {
132             #########
133             # already absolute
134             #
135 1         4 return $url;
136             }
137              
138 2 100       6 if($url =~ m{^/}smx) {
139             #########
140             # yield $domain$url
141             #
142 1         5 return "$current_domain$url";
143             }
144              
145 1         4 return "$current_dir$url";
146             }
147              
148             1;
149             __END__