Bottlenose is a thin, well-tested, maintained, and powerful Python wrapper over the Amazon Product Advertising API. There is practically no overhead, and no magic (unless you add it yourself).
Before you get started, make sure you have both Amazon Product Advertising and AWS accounts. AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
and AWS_ASSOCIATE_TAG
are all from your Amazon Associate Account.
pip install bottlenose
or
python3 -m pip install bottlenose
Then, using your AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, and AWS_ASSOCIATE_TAG
:
import bottlenose
amazon = bottlenose.Amazon(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ASSOCIATE_TAG)
response = amazon.ItemLookup(ItemId="B007OZNUCE")
You can then parse the response
output to view item information.
The default Region
is set to US
(webservices.amazon.com
). To specify another endpoint,
simply set the Region
parameter with the request. For example, to specify the French
endpoint (webservices.amazon.fr
), set the Region parameter to FR
:
amazon = bottlenose.Amazon(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ASSOCIATE_TAG, Region='FR')
Supported values for the Region parameter are CA
, CN
, DE
, ES
, FR
, IN
, IT
, JP
, UK
, and US
(default).
Your Amazon Product Advertising account (AWS_ASSOCIATE_TAG
) must exist for the given endpoint, otherwise, you'll get an HTTP 400 error ('Bad Request').
response = amazon.ItemLookup(ItemId="B007OZNUCE")
response = amazon.ItemSearch(Keywords="Kindle 3G", SearchIndex="All")
response = amazon.ItemLookup(ItemId="1449372422", ResponseGroup="Images")
response = amazon.SimilarityLookup(ItemId="B007OZNUCE")
amazon = bottlenose.Amazon(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ASSOCIATE_TAG)
response = amazon.CartCreate(...)
response = amazon.CartAdd(CartId, ...)
response = amazon.CartGet(CartId, ...)
response = amazon.CartModify(ASIN, CartId,...)
response = amazon.CartClear(CartId, ...)
import bottlenose
amazon = bottlenose.Amazon(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ASSOCIATE_TAG)
response = amazon.ItemLookup(ItemId="0596520999", ResponseGroup="Images",
SearchIndex="Books", IdType="ISBN")
print(response)
# <?xml version="1.0" ?><ItemLookupResponse xmlns="http://webservices.amazon...
Here is another example.
response = amazon.ItemSearch(Keywords="Kindle 3G", SearchIndex="All")
# <?xml version="1.0" ?><ItemSearchResponse xmlns="http://webservices.amazon...
Bottlenose can also read your credentials from the environment automatically;
just set $AWS_ACCESS_KEY_ID
, $AWS_SECRET_ACCESS_KEY
and
$AWS_ASSOCIATE_TAG
.
Any valid API call from the following is supported (in addition to any others that may be added in the future). Just plug in appropriate request parameters for the operation you'd like to call, and you're good to go.
BrowseNodeLookup
CartAdd
CartClear
CartCreate
CartGet
CartModify
ItemLookup
ItemSearch
SimilarityLookup
You can refer here for a full listing of API calls to be made from Amazon.
For more information about these calls, please consult the Product Advertising API Developer Guide.
By default, API calls return the response as a raw bytestring. You can change
this with the Parser
constructor argument. The parser is a callable that
takes a single argument, the response as a raw bytestring, and returns the
parsed response in a format of your choice.
For example, to parse responses with BeautifulSoup:
import bottlenose
from bs4 import BeautifulSoup
amazon = bottlenose.Amazon(
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ASSOCIATE_TAG,
Parser=lambda text: BeautifulSoup(text, 'xml')
)
results = amazon.ItemLookup(ItemId="0198596790", ResponseGroup="SalesRank")
print(results.find('SalesRank').string)
# 168088
Amazon strictly limits the query rate on its API (by default, one query
per second per associate tag). If you have a batch of non-urgent queries, you
can use the MaxQPS
argument to limit them to no more than a certain rate;
any faster, and bottlenose will sleep()
until it is time to make the next
API call.
Generally, you want to be just under the query limit, for example:
amazon = bottlenose.Amazon(MaxQPS=0.9)
If some other code is also querying the API with your associate tag (for example, a website backend), you'll want to choose an even lower value for MaxQPS.
You can often get a major speedup by caching API queries. Use the CacheWriter
and CacheReader
constructor arguments.
CacheWriter
is a callable that takes two arguments, a cache url, and the
raw response (a bytestring). It will only be called after successful queries.
CacheReader
is a callable that takes a single argument, a cache url, and
returns a (cached) raw response, or None
if there is nothing cached.
The cache url is the actual query URL with authentication information removed. For example:
http://webservices.amazon.com/onca/xml?Keywords=vacuums&Operation=ItemSearch&Region=US&ResponseGroup=SearchBins&SearchIndex=All&Service=AWSECommerceService&Version=2013-08-01
Example code:
def write_query_to_db(cache_url, data):
...
def read_query_from_db(cache_url):
...
amazon = bottlenose.Amazon(CacheWriter=write_query_to_db,
CacheReader=read_query_from_db)
Note that Amazon's Product Advertising API Agreement only allows you to cache queries for up to 24 hours.
Sometimes the Amazon API returns errors; for example, if you have gone over
your query limit, you'll get a 503. The ErrorHandler
constructor argument
gives you a way to keep track of such errors, and to retry queries when you
receive a transient error.
ErrorHandler
should be a callable that takes a single argument, a dictionary
with these keys:
api_url
minus authentication informationHTTPError
or URLError
)If your ErrorHandler
returns true, the query will be retried. Here's some
example code that does exponential backoff after throttling:
import random
import time
from urllib2 import HTTPError
def error_handler(err):
ex = err['exception']
if isinstance(ex, HTTPError) and ex.code == 503:
time.sleep(random.expovariate(0.1))
return True
amazon = bottlenose.Amazon(ErrorHandler=error_handler)
Apache License, Version 2.0. See LICENSE for details.