| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  |  | 
| 2 |  |  |  |  |  |  | # $Id: Completed.pm,v 1.36 2014-09-09 03:07:47 Martin Exp $ | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | =head1 NAME | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | WWW::Search::Ebay::Completed - backend for searching completed auctions on www.ebay.com | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | use WWW::Search; | 
| 11 |  |  |  |  |  |  | my $oSearch = new WWW::Search('Ebay::Completed'); | 
| 12 |  |  |  |  |  |  | my $sQuery = WWW::Search::escape_query("Yakface"); | 
| 13 |  |  |  |  |  |  | $oSearch->native_query($sQuery); | 
| 14 |  |  |  |  |  |  | $oSearch->login('ebay_username', 'ebay_password'); | 
| 15 |  |  |  |  |  |  | while (my $oResult = $oSearch->next_result()) | 
| 16 |  |  |  |  |  |  | { print $oResult->url, "\n"; } | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | This class is a Ebay specialization of L. | 
| 21 |  |  |  |  |  |  | It handles making and interpreting Ebay searches | 
| 22 |  |  |  |  |  |  | F. | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | This class exports no public interface; all interaction should | 
| 25 |  |  |  |  |  |  | be done through L objects. | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | =head1 NOTES | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | You MUST call the login() method with your eBay username and password | 
| 30 |  |  |  |  |  |  | before trying to fetch any results. | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | The search is done against completed auctions only. | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | The query is applied to TITLES only. | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | See the NOTES section of L for a description of the results. | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | =head1 METHODS | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | =cut | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | ##################################################################### | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | package WWW::Search::Ebay::Completed; | 
| 45 |  |  |  |  |  |  |  | 
| 46 | 3 |  |  | 3 |  | 244545 | use strict; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 67 |  | 
| 47 | 3 |  |  | 3 |  | 9 | use warnings; | 
|  | 3 |  |  |  |  | 3 |  | 
|  | 3 |  |  |  |  | 53 |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 | 3 |  |  | 3 |  | 9 | use Carp; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 138 |  | 
| 50 | 3 |  |  | 3 |  | 10 | use Date::Manip; | 
|  | 3 |  |  |  |  | 3 |  | 
|  | 3 |  |  |  |  | 490 |  | 
| 51 |  |  |  |  |  |  | # We need the version that was fixed to look for "Free Shipping": | 
| 52 | 3 |  |  | 3 |  | 1040 | use WWW::Search::Ebay 2.247; | 
|  | 3 |  |  |  |  | 28083 |  | 
|  | 3 |  |  |  |  | 164 |  | 
| 53 | 3 |  |  | 3 |  | 1252 | use WWW::Ebay::Session; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 90 |  | 
| 54 | 3 |  |  | 3 |  | 10 | use base 'WWW::Search::Ebay'; | 
|  | 3 |  |  |  |  | 3 |  | 
|  | 3 |  |  |  |  | 421 |  | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | our | 
| 57 |  |  |  |  |  |  | $VERSION = do { my @r = (q$Revision: 1.36 $ =~ /\d+/g); sprintf "%d."."%03d" x $#r, @r }; | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | our $MAINTAINER = 'Martin Thurn '; | 
| 60 |  |  |  |  |  |  |  | 
| 61 | 3 |  |  | 3 |  | 14 | use constant DEBUG_FUNC => 0; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 488 |  | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | sub _native_setup_search | 
| 64 |  |  |  |  |  |  | { | 
| 65 | 0 |  |  | 0 |  |  | my ($self, $native_query, $rhOptsArg) = @_; | 
| 66 | 0 |  | 0 |  |  |  | $rhOptsArg ||= {}; | 
| 67 | 0 | 0 |  |  |  |  | unless (ref($rhOptsArg) eq 'HASH') | 
| 68 |  |  |  |  |  |  | { | 
| 69 | 0 |  |  |  |  |  | carp " --- second argument to _native_setup_search should be hashref, not arrayref"; | 
| 70 | 0 |  |  |  |  |  | return undef; | 
| 71 |  |  |  |  |  |  | } # unless | 
| 72 |  |  |  |  |  |  | # As of August 2014: | 
| 73 |  |  |  |  |  |  | # http://www.ebay.com/sch/i.html?_from=R40&_sacat=0&_nkw=playboy+october+1977&LH_Complete=1&rt=nc | 
| 74 | 0 |  | 0 |  |  |  | $self->{search_host} ||= 'http://www.ebay.com'; | 
| 75 | 0 |  | 0 |  |  |  | $self->{search_path} ||= q{/sch/i.html}; | 
| 76 | 0 | 0 |  |  |  |  | $self->{_options}->{_nkw} = $native_query if ($native_query ne q{}); | 
| 77 | 0 |  |  |  |  |  | $self->{_options}->{LH_Complete} = 1; | 
| 78 | 0 |  |  |  |  |  | $self->{_options}->{_ipg} = 200; | 
| 79 | 0 |  |  |  |  |  | return $self->SUPER::_native_setup_search($native_query, $rhOptsArg); | 
| 80 |  |  |  |  |  |  | } # _native_setup_search | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | =head2 login | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | Takes two string arguments, | 
| 86 |  |  |  |  |  |  | the eBay userid and the eBay password. | 
| 87 |  |  |  |  |  |  | (See WWW::Search for more information.) | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | =cut | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | sub login | 
| 92 |  |  |  |  |  |  | { | 
| 93 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 94 | 0 |  |  |  |  |  | my ($sUserID, $sPassword) = @_; | 
| 95 | 0 | 0 |  |  |  |  | if (ref $self->{__ebay__session__}) | 
| 96 |  |  |  |  |  |  | { | 
| 97 | 3 |  |  | 3 |  | 14 | use Data::Dumper; | 
|  | 3 |  |  |  |  | 3 |  | 
|  | 3 |  |  |  |  | 1221 |  | 
| 98 | 0 |  |  |  |  |  | DEBUG_FUNC && print STDERR " +   login() was already called, I have these cookies:", Dumper($self->{__ebay__session__}->cookie_jar); | 
| 99 | 0 |  |  |  |  |  | return 1; | 
| 100 |  |  |  |  |  |  | } # if | 
| 101 | 0 |  |  |  |  |  | DEBUG_FUNC && print STDERR " + Ebay::Completed::login($sUserID)\n"; | 
| 102 |  |  |  |  |  |  | # Make sure we keep the cookie(s) from ebay.com: | 
| 103 | 0 |  |  |  |  |  | my $oJar = new HTTP::Cookies; | 
| 104 | 0 |  |  |  |  |  | $self->cookie_jar($oJar); | 
| 105 | 0 |  |  |  |  |  | my $oES = new WWW::Ebay::Session($sUserID, $sPassword); | 
| 106 | 0 | 0 |  |  |  |  | return undef unless ref($oES); | 
| 107 | 0 |  |  |  |  |  | $oES->cookie_jar($oJar); | 
| 108 | 0 |  |  |  |  |  | $oES->user_agent; | 
| 109 |  |  |  |  |  |  | # Save our Ebay::Session object for later use, but give it a rare | 
| 110 |  |  |  |  |  |  | # name so that nobody mucks with it: | 
| 111 | 0 |  |  |  |  |  | $self->{__ebay__session__} = $oES; | 
| 112 | 0 |  |  |  |  |  | return 1; | 
| 113 |  |  |  |  |  |  | } # login | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | =head2 http_request | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | This method does the heavy-lifting of fetching encrypted pages from ebay.com. | 
| 119 |  |  |  |  |  |  | (See WWW::Search for more information.) | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | =cut | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | sub http_request | 
| 124 |  |  |  |  |  |  | { | 
| 125 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 126 |  |  |  |  |  |  | # Make sure we replicate the arguments of WWW::Search::http_request: | 
| 127 | 0 |  |  |  |  |  | my ($method, $sURL) = @_; | 
| 128 | 0 |  |  |  |  |  | DEBUG_FUNC && print STDERR " + Ebay::Completed::http_request($method,$sURL)\n"; | 
| 129 | 0 |  |  |  |  |  | my $oES = $self->{__ebay__session__}; | 
| 130 | 0 | 0 |  |  |  |  | unless (ref $oES) | 
| 131 |  |  |  |  |  |  | { | 
| 132 | 0 |  |  |  |  |  | carp " --- http_request() was called before login()?"; | 
| 133 | 0 |  |  |  |  |  | return undef; | 
| 134 |  |  |  |  |  |  | } # unless | 
| 135 | 0 |  |  |  |  |  | $oES->fetch_any_ebay_page($sURL, 'wsec-page'); | 
| 136 | 0 |  |  |  |  |  | return $oES->response; | 
| 137 |  |  |  |  |  |  | } # http_request | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | sub _preprocess_results_page | 
| 140 |  |  |  |  |  |  | { | 
| 141 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 142 | 0 |  |  |  |  |  | my $sPage = shift; | 
| 143 |  |  |  |  |  |  | # For debugging: | 
| 144 | 0 |  |  |  |  |  | print STDERR $sPage; | 
| 145 | 0 |  |  |  |  |  | exit 88; | 
| 146 |  |  |  |  |  |  | } # preprocess_results_page | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | sub _columns | 
| 149 |  |  |  |  |  |  | { | 
| 150 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 151 |  |  |  |  |  |  | # This is for basic USA eBay: | 
| 152 | 0 |  |  |  |  |  | return qw( price bids enddate ); | 
| 153 |  |  |  |  |  |  | } # _columns | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | sub _parse_enddate | 
| 156 |  |  |  |  |  |  | { | 
| 157 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 158 | 0 |  |  |  |  |  | my $oTDdate = shift; | 
| 159 | 0 |  |  |  |  |  | my $hit = shift; | 
| 160 | 0 | 0 |  |  |  |  | if (! ref $oTDdate) | 
| 161 |  |  |  |  |  |  | { | 
| 162 | 0 |  |  |  |  |  | return 0; | 
| 163 |  |  |  |  |  |  | } | 
| 164 | 0 |  |  |  |  |  | my $s = $oTDdate->as_text; | 
| 165 | 0 | 0 |  |  |  |  | print STDERR " DDD   TDdate ===$s===\n" if 1 < $self->{_debug}; | 
| 166 | 0 |  |  |  |  |  | $s =~ s/END\sDATE://i; | 
| 167 |  |  |  |  |  |  | # Thanks to Jay for this fix: | 
| 168 | 0 |  |  |  |  |  | $s =~ s/TIME\s*LEFT://i; | 
| 169 |  |  |  |  |  |  | # I don't know why there are sometimes weird characters in there: | 
| 170 | 0 |  |  |  |  |  | $s =~ s!Â!!g; | 
| 171 | 0 |  |  |  |  |  | $s =~ s!Â!!g; | 
| 172 |  |  |  |  |  |  | # Convert nbsp to regular space: | 
| 173 | 0 |  |  |  |  |  | $s =~ s!\240!\040!g; | 
| 174 | 0 |  |  |  |  |  | my $date = ParseDate($s); | 
| 175 | 0 | 0 |  |  |  |  | print STDERR " DDD     date ===$date===\n" if 1 < $self->{_debug}; | 
| 176 | 0 |  |  |  |  |  | my $sDate = $self->_format_date($date); | 
| 177 | 0 |  |  |  |  |  | $hit->end_date($sDate); | 
| 178 | 0 |  |  |  |  |  | return 1; | 
| 179 |  |  |  |  |  |  | } # _parse_enddate | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | 1; | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | To make new back-ends, see L. | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | =head1 CAVEATS | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | =head1 BUGS | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | Please tell the author if you find any! | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | =head1 AUTHOR | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | Thanks to Troy Arnold > for figuring out how to do this search. | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | Maintained by Martin Thurn, C, L. | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | =head1 LEGALESE | 
| 200 |  |  |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED | 
| 202 |  |  |  |  |  |  | WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | 
| 203 |  |  |  |  |  |  | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | =cut | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | __END__ |