File Coverage

blib/lib/Email/Extractor.pm
Criterion Covered Total %
statement 55 76 72.3
branch 4 12 33.3
condition 0 6 0.0
subroutine 12 14 85.7
pod 7 7 100.0
total 78 115 67.8


line stmt bran cond sub pod time code
1             package Email::Extractor;
2             $Email::Extractor::VERSION = '0.01';
3              
4             # ABSTRACT: Fast email crawler
5              
6              
7 1     1   49323 use HTML::Encoding 'encoding_from_html_document';
  1         15164  
  1         63  
8 1     1   597 use List::Compare;
  1         14712  
  1         30  
9 1     1   8 use List::Util qw(uniq);
  1         2  
  1         80  
10 1     1   338 use Email::Find;
  1         84217  
  1         95  
11 1     1   449 use Mojo::DOM;
  1         91414  
  1         33  
12              
13 1     1   456 use Email::Extractor::Utils qw[:ALL];
  1         3  
  1         970  
14              
15              
16             sub new {
17 1     1 1 66 my ( $class, %param ) = @_;
18 1         7 $param{ua} = LWP::UserAgent->new;
19 1 50       2301 $param{only_lang} = 'ru' if !defined $param{only_lang};
20 1         5 bless {%param}, $class;
21             }
22              
23              
24             sub search_until_attempts {
25 0     0 1 0 my ( $self, $uri, $attempts ) = @_;
26              
27 0 0       0 $attempts = 10 if !defined $attempts;
28 0         0 my $links_checked = 1;
29 0         0 my $a = $self->get_emails_from_uri($uri);
30              
31 0 0       0 return $a if @$a;
32              
33 0   0     0 while ( !@$a && $links_checked <= $attempts )
34             { # but no more than 10 iterations
35              
36 0         0 my $urls = $crawler->extract_contact_links;
37 0         0 for my $u (@$urls) {
38 0         0 $a = $crawler->get_emails_from_uri($u);
39 0         0 $links_checked++;
40             }
41             }
42              
43 0         0 $self->{last_attempts} = $links_checked;
44 0         0 return $a;
45             }
46              
47              
48             sub get_emails_from_uri {
49 3     3 1 2480 my ( $self, $addr ) = @_;
50 3         8 @emails = ();
51 3         8 $self->{last_uri} = $addr;
52 3         10 my $text = load_addr_to_str($addr);
53             $self->{last_text} =
54 3         631 $text; # store html in memory to speed up further search
55             my $finder = Email::Find->new(
56             sub {
57 4     4   53049 my ( $email, $orig_email ) = @_;
58 4         13 push @emails, $orig_email;
59             }
60 3         30 );
61 3         27 $finder->find( \$text );
62 3         4330 @emails = uniq @emails;
63 3         28 return \@emails;
64             }
65              
66              
67             sub extract_contact_links {
68 6     6 1 1122 my ( $self, $text ) = @_;
69              
70 6 50       17 $text = $self->{last_text} if !defined $text;
71              
72 6         18 my $all_links = find_all_links($text);
73 6         1168 $self->{last_all_links} = $all_links;
74              
75             # TO-DO: do not remove links on social networks since there can be email too
76 6 50       14 if ( $self->{last_uri} ) {
77 0         0 $all_links = remove_external_links( $all_links, $self->{last_uri} );
78 0         0 $all_links = absolutize_links_array( $all_links, $self->{last_uri} );
79             }
80              
81 6         14 $all_links = remove_query_params($all_links);
82 6         13 $all_links = drop_asset_links($all_links);
83 6         13 $all_links = drop_anchor_links($all_links);
84              
85 6         9 my @potential_contact_links;
86              
87 6 50       14 if ( $self->{only_lang} ) {
88 6         10 my $contacts_loc = $self->contacts->{ $self->{only_lang} };
89             push @potential_contact_links,
90 6         13 @{ find_links_by_text( $text, $contacts_loc ) };
  6         9  
91             }
92             else {
93 0         0 for my $c ( @{ $self->contacts } ) {
  0         0  
94 0         0 my $res = find_links_by_text( $text, $c );
95 0         0 push @potential_contact_links, @$res;
96             }
97             }
98              
99 6         284 my $grep_url_expr = join( '|', $self->url_with_contacts );
100             my @potential_contact_links_by_url =
101 6         12 grep { $_ =~ /$grep_url_expr/ } @$all_links;
  6         45  
102              
103 6         13 my @contact_links =
104             ( @potential_contact_links_by_url, @potential_contact_links );
105 6         15 @contact_links = uniq @contact_links;
106              
107             $self->{non_contact_links} =
108 6         31 List::Compare->new( $all_links, \@contact_links )->get_symdiff;
109              
110 6         604 return \@contact_links;
111              
112             }
113              
114              
115             sub contacts {
116             return {
117             'en' => 'Contacts',
118             'ru' => 'Контакты',
119             };
120             }
121              
122              
123             sub url_with_contacts {
124 6     6 1 15 return qw/
125             contacts
126             kontaktyi
127             kontakty
128             about
129             /;
130             }
131              
132              
133             sub get_encoding {
134             my ( $self, $html ) = @_;
135             my $html_to_check = $html || $self->{last_text};
136             return encoding_from_html_document($html_to_check);
137             }
138              
139              
140             sub contacts {
141             return {
142 6     6 1 18 'en' => 'Contacts',
143             'ru' => 'Контакты',
144             };
145             }
146              
147              
148             sub get_encoding {
149 0     0 1   my ( $self, $html ) = @_;
150 0   0       my $html_to_check = $html || $self->{last_text};
151 0           return encoding_from_html_document($html_to_check);
152             }
153              
154             1;
155              
156             __END__