Being perfection herself, my wife loves books, and as a loving and dutiful husband, her Amazon wishlist is required reading for Christmas, birthdays, and all other occasions. But keeping track of the wishlist is a pain if I have to trudge over to Amazon every time. Far better to have my feed reader do it for me, with the help of a little script. Figure 10-1 shows my wishlist to give you an idea of what one looks like.
This feed uses the Amazon Web Services API to do its evil work. This
can be either REST- or SOAP-based, so you can choose your own
preferred poison. For fun, I’ll do this using the
REST interface, and then using XML::Simple
to
parse the XML. My idea of fun might not be the same as yours, of
course.
As always, we fire up the script with the loading of the modules and
the setting of some global variables: the obligatory
use
strict;
and
use
warnings;
, and the required
Amazon API subscription key. You’ll need to get your
own from http://www.amazon.com/gp/aws/landing.html.
use strict; use warnings; use XML::RSS; use XML::Simple; use LWP::Simple qw(!head); use CGI qw(:standard); use Getopt::Long; use Date::Manip; my $amazon_subscription_id = "xxxxxxxxxxxxxxxxxx"; my $rss = new XML::RSS( version => '2.0' );
As this script is running as a CGI application, it requires the Amazon Wishlist ID as a parameter. This allows you to use the same script many times over for each of the lists you want to monitor. Let’s make the parameter compulsory, naturally.
my $cgi = CGI::new( ); my $list_id = $cgi->param('list'),
Now, run the query via the Amazon Web Services REST interface. This
takes a specifically formed URI and returns an XML document.
We’ll retrieve this using the
LWP::Simple
module:
my $query_url = "http://webservices.amazon.com/onca/ xml?Service=AWSProductData&SubscriptionId=$amazon_subscription_ id&Operation=ListLookup&ProductPage=15&ListType=WishList&ListId=$list_ id&ResponseGroup=Request,ListItems"; my $wishlist_in_xml = get("$query_url");
and place it into the Parser:
my $parser = XMLin("$wishlist_in_xml") or die ("Could not parse file");
This produces an array of the items within the wishlist, albeit still stored within the XML format returned by the REST query. That format looks like this:
<ListItem> <ListItemId>I2MNVARC9PUUA7</ListItemId> <DateAdded>2004-11-03</DateAdded> <QuantityDesired>1</QuantityDesired> <QuantityReceived>0</QuantityReceived> <Item> <ASIN>0875963528</ASIN> <ItemAttributes> <Title>Hal Higdon's How to Train</Title> </ItemAttributes> </Item> </ListItem>
So now you need to take the relevant bits of that information and
throw it into the feed. For the taking is the title, the date, and
the ASIN number—Amazon’s internal system for
identifying its stock. Use this to provide a link. For a change of
pace, let’s use a different XML parsing method, too.
XML::Simple
is tremendously useful for this sort
of thing.
Now, we’ll add in some code to create the correct
date, based on the date the item was added to the wishlist. Amazon
returns the date in the format YYYY-MM-DD, but RSS 2.0 insists on the
format Sun, 19 May 2002 15:21:36 GMT
. For the sake
of sanity, assume all the dates Amazon gives are at exactly midnight.
We need to do some date manipulation, and what better than
Date::Manip
to do this? Under its
UnixDate
function, the code %g
is exactly the right format for RSS 2.0. Nifty, no?
foreach my $item (@{$parser->{'Lists'}->{'List'}->{'ListItem'}}) { #my $date = &UnixDate("midnight $item->{'Item'}->{'DateAdded'}","%c, %e %b %Y"); $rss->add_item( title => "$item->{'Item'}->{'ItemAttributes'}->{'Title'}", link => "http://www.amazon.com/exec/obidos/tg/detail/-/$item->{'Item'}->{'ASIN'}", description => "$item->{'Item'}->{'ItemAttributes'}->{'Title'}", pubDate => &UnixDate("midnight $item->{'DateAdded'}","%g") ); }
Then, as ever, it’s just a matter of adding in the channel information and serving the thing out with the correct MIME type:
$rss->channel( title => "Amazon Wishlist, $list_id", link => "http://www.amazon.com", description => "An RSS feed of the Amazon Wishlist, id number $list_id" ); print header('application/xml+rss'), print $rss->as_string;
#!/usr/bin/perl use strict; use warnings; use XML::RSS; use XML::Simple; use LWP::Simple qw(!head); use CGI qw(:standard); use Getopt::Long; use Date::Manip; my $amazon_subscription_id = "08R1SHPFGCA8VYT9P802"; my $rss = new XML::RSS( version => '2.0' ); my $cgi = CGI::new( ); my $list_id = $cgi->param('list'), my $query_url = "http://webservices.amazon.com/onca/ xml?Service=AWSProductData&SubscriptionId=$amazon_subscription_ id&Operation=ListLookup&ProductPage=15&ListType=WishList&ListId=$list_ id&ResponseGroup=Request,ListItems"; my $wishlist_in_xml = get("$query_url"); my $parser = XMLin("$wishlist_in_xml") or die ("Could not parse file"); foreach my $item (@{$parser->{'Lists'}->{'List'}->{'ListItem'}}) { $rss->add_item( title => "$item->{'Item'}->{'ItemAttributes'}->{'Title'}", link => "http://www.amazon.com/exec/obidos/tg/detail/-/$item->{'Item'}->{'ASIN'}", description => "$item->{'Item'}->{'ItemAttributes'}->{'Title'}", pubDate => &UnixDate("midnight $item->{'DateAdded'}","%g") ); } $rss->channel( title => "Amazon Wishlist, $list_id", link => "http://www.amazon.com", description => "An RSS feed of the Amazon Wishlist, id number $list_id" ); print header('application/xml+rss'), print $rss->as_string;
3.138.114.132