File Coverage

blib/lib/LWP/UserAgent/Throttled.pm
Criterion Covered Total %
statement 31 44 70.4
branch 3 16 18.7
condition 1 8 12.5
subroutine 8 9 88.8
pod 3 3 100.0
total 46 80 57.5


line stmt bran cond sub pod time code
1             package LWP::UserAgent::Throttled;
2              
3 3     3   842215 use warnings;
  3         6  
  3         196  
4 3     3   19 use strict;
  3         6  
  3         132  
5 3     3   1810 use LWP;
  3         195764  
  3         137  
6 3     3   32 use LWP::UserAgent;
  3         11  
  3         81  
7 3     3   18 use Time::HiRes;
  3         6  
  3         27  
8 3     3   167 use URI;
  3         6  
  3         1637  
9              
10             our @ISA = ('LWP::UserAgent');
11              
12             =head1 NAME
13              
14             LWP::UserAgent::Throttled - Throttle requests to a site
15              
16             =head1 VERSION
17              
18             Version 0.14
19              
20             =cut
21              
22             our $VERSION = '0.14';
23              
24             =head1 SYNOPSIS
25              
26             Some sites with REST APIs, such as openstreetmap.org, will blacklist you if you do too many requests.
27             LWP::UserAgent::Throttled is a sub-class of LWP::UserAgent.
28              
29             use LWP::UserAgent::Throttled;
30             my $ua = LWP::UserAgent::Throttled->new();
31             $ua->throttle({ 'www.example.com' => 5 });
32             print $ua->get('http://www.example.com/page1.html');
33             sleep (2);
34             print $ua->get('http://www.example.com/page2.html'); # Will wait at least 3 seconds before the GET is sent
35              
36             =cut
37              
38             =head1 SUBROUTINES/METHODS
39              
40             =head2 send_request
41              
42             See L.
43              
44             =cut
45              
46             sub send_request {
47             # my ($request, $arg, $size) = @_;
48              
49 1     1 1 9939 my $self = shift;
50 1         4 my $request = $_[0];
51 1         4 my $host = lc(URI->new($request->uri)->host()); # Normalize the URL
52              
53 1 0 33     161 if((defined($self->{'throttle'})) && $self->{'throttle'}{$host} && $self->{'lastcallended'}{$host}) {
      0        
54             # Can't set a negative throttle
55 0 0       0 die "Throttle for $host must be >= 0" unless $self->{'throttle'}{$host} >= 0;
56              
57 0         0 my $waittime = $self->{'throttle'}{$host} - (Time::HiRes::time() - $self->{'lastcallended'}{$host});
58              
59 0 0       0 if($waittime > 0) {
60 0         0 Time::HiRes::usleep($waittime * 1e6);
61             }
62             }
63 1         2 my $rc;
64 1 50       3 if(defined($self->{'_ua'})) {
65 1         5 $rc = $self->{'_ua'}->send_request(@_);
66             } else {
67 0         0 $rc = $self->SUPER::send_request(@_);
68             }
69 1         13 $self->{'lastcallended'}{$host} = Time::HiRes::time();
70 1         4 return $rc;
71             }
72              
73             =head2 throttle
74              
75             Get/set the number of seconds between each request for sites.
76              
77             my $ua = LWP::UserAgent::Throttled->new();
78             $ua->throttle({ 'search.cpan.org' => 0.1, 'www.example.com' => 1 });
79             print $ua->throttle('search.cpan.org'), "\n"; # prints 0.1
80             print $ua->throttle('perl.org'), "\n"; # prints 0
81              
82             When setting a throttle it returns itself,
83             so you can daisy chain messages.
84              
85             =cut
86              
87             sub throttle {
88 0     0 1 0 my ($self, $args) = @_;
89              
90 0 0       0 return unless(defined($args));
91              
92 0 0       0 if(ref($args) eq 'HASH') {
93             # Merge the new throttles in with the previous throttles
94 0 0       0 $self->{throttle} = { %{$self->{throttle} || {}}, %{$args} };
  0         0  
  0         0  
95 0         0 return $self;
96             }
97              
98 0   0     0 return $self->{throttle}{$args} || 0;
99             }
100              
101             =head2 ua
102              
103             Get/set the user agent if you wish to use that rather than itself
104              
105             use LWP::UserAgent::Cached;
106              
107             $ua->ua(LWP::UserAgent::Cached->new(cache_dir => '/home/home/.cache/lwp-cache'));
108             my $resp = $ua->get('https://www.nigelhorne.com'); # Throttles, then checks cache, then gets
109              
110             =cut
111              
112             sub ua {
113 2     2 1 156851 my($self, $ua) = @_;
114              
115 2 100       6 if($ua) {
116 1         6 $self->{_ua} = $ua;
117             }
118              
119 2         8 return $self->{_ua};
120             }
121              
122             =head1 AUTHOR
123              
124             Nigel Horne, C<< >>
125              
126             =head1 BUGS
127              
128             Please report any bugs or feature requests to C,
129             or through the web interface at
130             L.
131             I will be notified, and then you'll
132             automatically be notified of progress on your bug as I make changes.
133              
134             Redirects to other domains can confuse it, so you need to program those manually.
135              
136             =head1 SEE ALSO
137              
138             L
139              
140             =head1 SUPPORT
141              
142             This module is provided as-is without any warranty.
143              
144             You can find documentation for this module with the perldoc command.
145              
146             perldoc LWP::UserAgent::Throttled
147              
148             You can also look for information at:
149              
150             =over 4
151              
152             =item * MetaCPAN
153              
154             L
155              
156             =item * RT: CPAN's request tracker
157              
158             L
159              
160             =item * CPANTS
161              
162             L
163              
164             =item * CPAN Testers' Matrix
165              
166             L
167              
168             =item * CPAN Testers Dependencies
169              
170             L
171              
172             =back
173              
174             =head1 LICENSE AND COPYRIGHT
175              
176             Copyright 2017-2025 Nigel Horne.
177              
178             This program is released under the following licence: GPL2
179              
180             =cut
181              
182             1; # End of LWP::Throttle