File Coverage

blib/lib/WWW/Orkut/Spider.pm
Criterion Covered Total %
statement 21 151 13.9
branch 0 28 0.0
condition n/a
subroutine 7 21 33.3
pod 14 14 100.0
total 42 214 19.6


!x) { $xml .= xml($tag,$1); }
line stmt bran cond sub pod time code
1             package WWW::Orkut::Spider;
2              
3 1     1   48640 use 5.008002;
  1         3  
  1         45  
4 1     1   86 use strict;
  1         2  
  1         84  
5              
6             require Exporter;
7 1     1   1054 use AutoLoader qw(AUTOLOAD);
  1         2516  
  1         6  
8              
9             our @ISA = qw(Exporter);
10              
11             # Items to export into callers namespace by default. Note: do not export
12             # names by default without a very good reason. Use EXPORT_OK instead.
13             # Do not simply export all your public functions/methods/constants.
14              
15             # This allows declaration use WWW::Orkut::Spider ':all';
16             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
17             # will save memory.
18             our %EXPORT_TAGS = ( 'all' => [ qw(
19             new
20             login
21             logout
22             name
23             users
24             get_myfriends
25             get_hisfriends
26             get_friendsfriends
27             get_xml_friendslist
28             get_xml_communities
29             get_xml_profile
30            
31             ) ] );
32              
33             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
34              
35             our @EXPORT = qw(
36            
37             );
38              
39             our $VERSION = '0.03';
40              
41              
42             # Preloaded methods go here.
43 1     1   1787 use WWW::Mechanize;
  1         252262  
  1         42  
44 1     1   12 use HTML::Entities;
  1         2  
  1         85  
45 1     1   5 use HTML::Entities qw(encode_entities_numeric);
  1         2  
  1         41  
46 1     1   7 use Carp;
  1         1  
  1         1694  
47             =head1 NAME
48              
49             WWW::Orkut::Spider - Perl extension for spidering the orkut community
50              
51             =head1 SYNOPSIS
52              
53             use WWW::Orkut::Spider;
54             my $orkut = WWW::Orkut::Spider->new;
55             $orkut->login($user,$pass);
56             $orkut->get_hisfriends($uid);
57             print $orkut->get_xml_profile($uid);
58              
59              
60             =head1 DESCRIPTION
61              
62             WWW::Orkut::Spider uses WWW:Mechanize to scrape orkut.com.
63             Output is a simple xml format containing friends, communities and profiles for a given Orkut UID.
64              
65             - Access to orkut.com via WWW::Mechanize
66             - Collects UIDs
67             - Fetches Profiles/Communities/Friends for a given UID
68             - Output via simple xml format
69              
70             =head2 new (proxy)
71              
72             You can specify a Proxy Server here
73             i.e: http://www.proxy.de:8080/
74             or: undef
75              
76             =cut
77             sub new {
78 0     0 1   my $class = shift;
79 0           my $self = {};
80 0           $self->{proxy} = shift;
81 0           $self->{useragent} = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Galeon/1.3.11a (Debian package 1.3.11a-2)';
82              
83 0           return bless $self,$class;
84             }
85              
86             =head2 login (user,pass)
87            
88             login orkut as user with pass
89             return undef if unseccessful
90              
91             =cut
92             sub login {
93 0     0 1   my $self=shift;
94 0           $self->{user}=shift;
95 0           $self->{pass}=shift;
96              
97 0           $self->{agent} = WWW::Mechanize->new( autocheck => 1,
98             agent => $self->{useragent},
99             );
100 0           $self->{agent}->proxy( 'http', $self->{proxy} );
101            
102             # get main page
103 0           $self->{agent}->get ('http://www.orkut.com/');
104 0 0         unless ($self->{agent}->success) {
105 0           croak "Can't even get the main page: ", $self->{agent}->response->status_line;
106 0           return;
107             }
108            
109             # submit login form
110 0           $self->{agent}->submit_form( fields => { u => $self->{user}, p => $self->{pass}, });
111 0           sleep 1;
112              
113             # goto home page
114 0 0         unless ( $self->{agent}->get("/Home.aspx") ) {
115 0           croak "cannot get users home page";
116 0           return;
117             }
118 0           return 1;
119             }
120              
121             =head2 logout
122            
123             logout of orkut
124              
125             =cut
126             sub logout {
127 0     0 1   my $self=shift;
128 0           $self->{agent}->follow('Logout');
129             }
130              
131             =head2 name (uid)
132            
133             return name of given known uid
134              
135             =cut
136             sub name {
137 0     0 1   my $self = shift;
138 0           my $uid = shift;
139 0           return $self->{users}{$uid};
140             }
141              
142             =head2 users
143            
144             return array with all known uids
145              
146             =cut
147             sub users {
148 0     0 1   my $self=shift;
149 0           return keys %{$self->{users}};
  0            
150             }
151              
152             =head2 xml (tag,value)
153            
154             return a simple
155             value
156              
157             =cut
158             sub xml {
159 0     0 1   my $tag = shift;
160 0           my $val = encode_entities_numeric(shift);
161 0           return "\t<$tag>$val\n";
162             }
163              
164             =head2 get_myfriends
165              
166             only after login
167             follow the link to friendslist
168             and get friends uids
169             return 1 if success
170              
171             =cut
172             sub get_myfriends {
173 0     0 1   my $self=shift;
174              
175 0 0         unless ( $self->{agent}->follow_link( url_regex => qr/FriendsList/ ) ) {
176 0           croak "cannot follow link to FriendsList";
177 0           return;
178             }
179 0           my $users = $self->follow_friends();
180 0           foreach (keys %{$users}) {
  0            
181 0           $self->{users}{$_} = $users->{$_};
182             }
183 0           return 1;
184             }
185              
186             =head2 get_hisfriends (uid)
187              
188             parse uid friends page for more uids
189              
190             =cut
191             sub get_hisfriends {
192 0     0 1   my $self=shift;
193 0           my $uid = shift;
194              
195 0 0         unless ( $self->{agent}->get("/FriendsList.aspx?uid=".$uid ) ) {
196 0           croak "cannot get FriendsList.aspx?uid=$uid";
197 0           return;
198             }
199 0           my $users = $self->follow_friends();
200 0           foreach (keys %{$users}) {
  0            
201 0           $self->{users}{$_} = $users->{$_};
202             }
203 0           return 1;
204             }
205              
206             =head2 follow_friends
207              
208             follow through all friends pages
209             called after GET of first friend page
210              
211             =cut
212             sub follow_friends {
213 0     0 1   my $self = shift;
214              
215             # get first page users
216 0           my $users = $self->parse_friends();
217              
218             # get avaible pages
219 0           my @links = $self->{agent}->find_all_links(url_regex=> qr/FriendsList.*uid/);
220 0           my @pages;
221 0           foreach my $l (@links) {
222 0           my $uid = $l->[0];
223 0 0         if ( $uid =~ m/\d+&pno=(\d+)$/ ) {
224 0 0         push @pages,$uid unless $1 eq '1';
225             }
226             }
227              
228             # pages
229 0           foreach my $p (@pages) {
230 0 0         unless ($self->{agent}->get('/'.$p)) {
231 0           croak "cannot get $p";
232             }
233 0           my $users_page = $self->parse_friends();
234 0           %{$users} = (%{$users},%{$users_page});
  0            
  0            
  0            
235             }
236              
237 0           return $users;
238             }
239              
240             =head2 parse_friends
241              
242             parse html page for friends uids
243             helper for follow friends
244             used after GET FriendList
245              
246             =cut
247             sub parse_friends {
248 0     0 1   my $self = shift;
249 0           my %users;
250 0           my @links = $self->{agent}->find_all_links(url_regex=> qr/FriendsList.*uid/);
251 0           foreach my $l (@links) {
252 0 0         next if $l->[1] =~ m/IMG/;
253 0 0         next if $l->[0] =~ m/\d+&pno=\d+/;
254 0           my $uid= $l->[0];
255 0           $uid =~ s/.*uid=(\d*).*/$1/;
256 0           $users{$uid}=encode_entities_numeric($l->[1]);
257             }
258              
259 0           return \%users;
260             }
261              
262             =head2 get_friendsfriends (n)
263              
264             iterate n times over found uids to find more friends
265             more than n=1 seems insane, unlikely to work
266             don't let your script crash in this function, WWW::Mechanize may decide to die if orkut.com gets one of its server failures
267             FIXME: logout/login all 50 requests may help
268              
269             =cut
270             sub get_friendsfriends {
271 0     0 1   my $self=shift;
272 0           my $n = shift;
273 0           my %friends;
274             my %lookup;
275              
276 0           for (my $i=0;$i<$n;$i++) {
277 0           %friends = undef;
278 0           %friends = %{$self->{users}};
  0            
279 0           foreach my $u (keys %friends) {
280 0 0         next if $lookup{$u};
281 0           $lookup{$u}+=1;
282 0 0         unless ( $self->{agent}->get("/FriendsList.aspx?uid=".$u) ) {
283 0           croak "cannot get FriendList of $u.";
284             }
285 0           my $users = $self->follow_friends();
286 0           foreach (keys %{$users}) {
  0            
287 0           $self->{users}{$_} = $users->{$_};
288             }
289             }
290             }
291             }
292              
293             =head2 get_xml_profile (uid)
294              
295             return profile of uid as simple xml
296              
297             =cut
298             sub get_xml_profile {
299 0     0 1   my $self = shift;
300 0           my $uid = shift;
301 0           my $xml;
302              
303             # get his profile
304 0           $self->{agent}->get("/Profile.aspx?uid=".$uid);
305 0           foreach ('relationship_status', 'birthday', 'age', 'here_for', 'children', 'ethnicity', 'political_view', 'humor', 'sexual_orientation', 'fashion', 'smoking','drinking','living', 'passions', 'sports', 'activities', 'books', 'music', 'tv_shows', 'movies', 'cuisines', 'email', 'country', 'IM', 'home_phone', 'address_line_1', 'address_line_2', 'webpage') {
306 0           my $tag = $_;
307 0           $tag =~ s/_/ /g;
308 0 0         if ( $self->{agent}->content() =~ m!>$tag:(.*?)
  0            
309             }
310              
311             # get his karma
312 0 0         if ( $self->{agent}->content() =~ m!lblKarma">.*?img/i_t(\d).*img/i_c(\d).*img/i_h(\d).*(\d+)!) {
313 0           $xml .= xml('trust',$1);
314 0           $xml .= xml('cool',$2);
315 0           $xml .= xml('hot',$3);
316 0           $xml .= xml('fans',$4);
317             }
318 0           return $xml;
319             }
320              
321             =head2 get_xml_communities (uid)
322              
323             return communities of uid as simple xml
324              
325             =cut
326             sub get_xml_communities {
327 0     0 1   my $self = shift;
328 0           my $uid = shift;
329 0           my $xml;
330              
331             # get his communities
332 0           $self->{agent}->get("/ProfileC.aspx?uid=".$uid);
333 0           my @comm = $self->{agent}->find_all_links(url_regex=> qr/Community.aspx?/);
334 0           my @fcomms;
335 0           foreach my $c (@comm) {
336 0           push @fcomms, encode_entities_numeric($c->[1]);
337             }
338 0           $xml .= xml('communities',join ',',@fcomms);
339 0           return $xml;
340             }
341              
342             =head2 get_xml_friendslist (uid)
343              
344             return friendslist of uid as simple xml
345              
346             =cut
347             sub get_xml_friendslist {
348 0     0 1   my $self = shift;
349 0           my $uid = shift;
350 0           my $xml;
351              
352             # similiar to 'get his friends'
353             # get first page
354 0 0         unless ($self->{agent}->get("/FriendsList.aspx?uid=".$uid)) {
355 0           croak "cannot get FriendsList.aspx?uid=$uid";
356             }
357              
358 0           my @fuids;
359 0           my $users = $self->follow_friends();
360 0           foreach (keys %{$users}) {
  0            
361 0           push @fuids, $_;
362             }
363              
364 0           $xml .= xml('friends',join ',',@fuids);
365 0           return $xml;
366             }
367              
368              
369             # Autoload methods go after =cut, and are processed by the autosplit program.
370              
371             1;
372             __END__