`Na szybko' zrobiłem trzy skrypty wykorzystujące Ebay REST API. Skrypty mają ułatwić wyszukiwanie oraz archiwizowanie interesujących mnie aukcji. Próbowałem wykorzystać do ww. celu gotowe narzędzie ale jakoś nic interesującego nie znalazłem. Bibioteka Net::eBay
jakaś taka słabo udokumentowana i nieporęczna mi się wydała podobnie jak WWW::Search::Ebay
. (Por. skrypt opisany np. tutaj.)
Najbardziej skomplikowany z moich skryptów wykorzystuje metodę FindItemsAdvanced
do wyszukania aukcji. Metoda FindItemsAdvanced
ma parametr MaxEntries
określający liczbę zwracanych aukcji. Parametr ten ma domyślną wartość 20
a maksymalną akceptowaną wartością jest 200
(jeżeli podamy 0
to metoda zwróci liczbę pasujących do zapytania aukcji). Jeżeli aukcji jest więcej niż wynosi wartość MaxEntries
, to aby ściągnąć kolejne aukcje metodę FindItemsAdvanced
trzeba wykonać wielokrotnie, podając odpowiednią wartość parametru PageNumber
. Przykładowo jeżeli aukcji jest 121, a wartość MaxEntries
wynosi 40, to trzeba FindItemsAdvanced
wykonać 4 razy.
Parametr ItemSort
ustala porządek sortowania. Wartość StartDate
tego parametru powoduje, że aukcje są posortowane według daty wstawienia na ebay (daty/czasy są definiowane w GMT oczywiście).
W związku z takim działaniem metody FindItemsAdvanced
skrypt ebay_rest_search.pl
najpierw ustala liczbę pasujących aukcji, a następnie pobiera kolejno strony w pętli do momentu aż znajdzie aukcję już pobraną (aukcje są przechowywane w haszu %IdxLog
, który jest przechowywany na dysku przy wykorzystaniu funkcji store
/retrieve
modułu Storable). Nowe aukcje są dodawane do hasza %IdxLog
:
## Uproszczony fragment skryptu:
while ( ($current_page >= 0) && ($current_page <= $last_page ) ) {
$current_page++;
$xml = make_call('search_text' => $search_text, 'per_page' => $MAX_PER_PAGE,
'site_id' => "$this_site_id", 'page' => $current_page);
my $xm = $xmlp->XMLin($xml, ForceArray => 0);
my $list = $xm ->{'SearchResult'}->{ItemArray}->{Item} ;
foreach $item ( @{$list} ) {
$item_id = $item->{'ItemID'};
if ( exists $IdxLog{ $item_id } ) {## zakończ
$current_page = -99; last ; }
else { $new_items++;
$IdxLog{ $item_id } = [ $item->{'Title'}, $item->{'StartTime'}, $item->{'EndTime'},
$item->{'GalleryURL'}, $item->{'ListingStatus'},
$item->{'ViewItemURLForNaturalSearch'}, $day_added ];
}
}
}
Metoda XMLin
jest z modułu XML::Simple
. Moduł ten definiuje prosty interfejs do dokumentów XML. Po wykonaniu XMLin
, zawartość dokumentu jest dostępna w postaci elementów zagnieżdżonych list/haszy. Można oczywiście analizować dokument XML w inny sposób, nie upieram się że XML::Simple
jest najlepszym pomysłem.
Uwaga: metoda FindItemsAdvanced
nie umożliwia przeszukania całej bazy eBay (odpowiednik wyszukiwanie zaawansowane->preferowana lokalizacja->cały świat). Parametr siteid
określa, który serwis eBay ma być przeszukany. Jeżeli podamy id=0
to zapytanie dotyczyć będzie ebay.com, a jeżeli id=212
, to ebay.com.pl, itd. Aby przeszukać cały ebay to trzeba wykonać FindItemsAdvanced
wielokrotnie.
Następnie hasz %IdxLog
jest przeglądany w pętli celem archiwizacji aukcji, które się zakończyły:
for $id (sort { $IdxLog{$a}[2] cmp $IdxLog{$b}[2] } keys %IdxLog) {
$end_time = $IdxLog{$id}[2]; # drugi element listy to czas zakończenia
$time_to_end = $now_in_seconds - ebaydate2seconds( $end_time );
if ($time_to_end > 0 && $status =~ /Active/) {# Aukcja zakończona
$result = `ebay_rest_item.pl -i $id`; ## ściągnij innym skryptem
if ($? > 0 ) { warn "Problems backuping $id\n"; } else {
$IdxLog{$id}[4] = 'Completed'; # zmień status na zakończoną
$completed_items++; }
}
}
Zmienna $now_in_seconds
, to liczba sekund od epoch a funkcja ebaydate2seconds
zmienia napis zawierający czas w formacie zwracanym w dokumencie XML na liczbę sekund od epoch. Jeżeli różnica czasu bieżącego a czasu zakończenia aukcji wskazuje, ze aukcja się zakończyła jest ona ściągana za pomocą skryptu ebay_rest_item
:
#!/usr/bin/perl
use LWP::Simple;
use Getopt::Long;
my $verbose = 1;
use lib "$ENV{HOME}/.ebay"; ## configuration files
GetOptions('item=s' => \$ebay_item_id, 'help' => \$print_help, );
unless ($ebay_item_id) { die "Usage: $0 -i <item_id>\n"; }
our $netebay_rc;
require("netebay.rc");
my $url = "http://open.api.ebay.com/shopping?callname=GetSingleItem" .
"&responseencoding=XML" .
"&appid=$EBayRC{p_appid}" .
"&siteid=0" .
"&version=525" .
"&ItemID=$ebay_item_id" .
"&IncludeSelector=Description,Details";
my $xml = get $url ;
## In a scalar context m//g iterates through the string, returning true each time
## it matches. If you modify the string in any way, the match position is reset.
my %Pics;
while ($xml =~ /<PictureURL>([^<>]+)<\/PictureURL>/mg) { $Pics{$1} = 1; }
my $pic, $ori_pic;
for $pic (keys %Pics ) {
$ori_pic = $pic; $ori_pic =~ s/\?/\\\?/g; # zmieniamy meta znaki: ?
$pic =~ s/\?[^\?]+$//g;
my ($content_type, $document_length, $modified_time, $expires, $server) = head($pic);
$pic_no++;
if ( $content_type =~ /image/ ) { $content_type =~ m/\/(.+)$/;
$local_file = "${ebay_item_id}_${pic_no}.$1"; }
else { $local_file = "${ebay_item_id}_${pic_no}.JPG?"; } ## problems with content_type
warn "Storing $pic in $ARCH_DIR/$local_file ... \n";
getstore($pic, "$ARCH_DIR/$local_file");
## zapisz lokalną nazwę jako atrybut
## Uwaga na metaznaki (? już jest obezwładniony):
$xml =~ s/<PictureURL>$ori_pic/<PictureURL local='$local_file'>$ori_pic/;
}
open (LOG, ">$ARCH_DIR/$ebay_item_id.xml" ) ||
die " ** cannot open $ARCH_DIR/$ebay_item_id.xml **";
print LOG "$xml\n";
Ten skrypt zapisuje po prostu dokument XML zwrócony przez metodę GetSingleItem
. Argumentem skryptu jest id aukcji. Jedyne utrudnienie związane jest z pobraniem zdjęć. Adresy URL do zdjęć są zdefiniowane wewnątrz elementów PictureURL
. Aby uprościć skrypt elementy te są wyszukiwane przy pomocy prostego wyrażenia regularnego. Konstrukcja:
while ($napis =~ /wzorzec/mg) { ## $1 zawiera dopasowany do wzorca napis }
Będzie dopasowywać wzorzec
do $napisu
iteracyjnie. W każdej iteracji zmienna $1
będzie zawierała kolejny napis pasujący do wzorca
. Aby powyższe działało prawidłowo $napis
nie może być modyfikowany wewnątrz pętli (i nie jest). Adresy URL są składowane w haszu %Pics
.
Teraz hasz %Pics
jest przeglądany w pętli. Zdjęcia są ściągane a dodatkowo dokument XML jest modyfikowany -- też za pomocą wyrażeń regularnych -- w taki sposób, że do elementu dodawana jest informacja o nazwie lokalnej zdjęcia. Nazwa lokalna jest tworzona automatycznie jako: ${ebay_item_id}_${pic_no}.$1
, gdzie ${pic_no}
jest kolejnym numerem zdjęcia dla aukcji o numerze ${ebay_item_id}
.
Ostatni skrypt jest najprostszy i drukuje fragment drzewa kategorii eBay (konkretnie podkategorie dla kategorii, której id podano jako argument skryptu). Korzeń drzewa ma id równe -1
.
#!/usr/bin/perl
use LWP::Simple;
use Getopt::Long;
use lib "$ENV{HOME}/.ebay"; ## configuration files
use $ebay_site_id = 'US'; ## 0 is US ebay
GetOptions( 'site=s' => \$ebay_site_id, 'category=i' => \$ebay_cat_id,
'help' => \$print_help, );
unless ($ebay_cat_id) {$ebay_cat_id = -1 } ## top-level
our $netebay_rc;
require("netebay.rc");
my $site_id_code = $Sites_Ids{$ebay_site_id};
my $url = "http://open.api.ebay.com/Shopping?callname=GetCategoryInfo" .
"&appid=$EBayRC{p_appid}" .
"&version=533" .
"&siteid=$site_id_code" .
"&CategoryID=$ebay_cat_id" .
"&IncludeSelector=ChildCategories";
print (get $url) . "\n" ;
Ten skrypt przyda się do udoskonalenia działania ebay_rest_search
, tak żeby przeszukiwania dotyczyły tylko wybranych kategorii. Niestety eBay nie ma jednolitej hierarchii kategorii. Ten sam przedmiot może być różnie klasyfikowany.
No i tyle. Pozostaje umieścić ebay_rest_search
w crontabie. Skrypty są tutaj.
Brak komentarzy:
Prześlij komentarz