Skip to content

Commit cf58ef8

Browse files
committed
First working version
1 parent 9d3440b commit cf58ef8

96 files changed

Lines changed: 18364 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,29 @@
1-
# python-amazon-paapi5
21
Amazon Product Advertising API V5 wrapper for Python 💰
2+
=======================================================
3+
A simple Python wrapper for the Amazon Product Advertising API version 5.
4+
5+
Features
6+
--------
7+
8+
* Object oriented interface for simple usage
9+
* Get information about a product through its ASIN
10+
* More coming in the future
11+
12+
Installation
13+
-------------
14+
15+
* Add this module to your project
16+
* PIP support coming in the future
17+
18+
Usage
19+
-----
20+
21+
from amazon.paapi import AmazonAPI
22+
amazon = AmazonAPI(KEY, SECRET, TAG, COUNTRY)
23+
product = amazon.get_product(asin)
24+
25+
26+
License
27+
-------
28+
29+
Copyright © 2019 Sergio Abad

amazon/paapi.py

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""Amazon Product Advertising API v5 wrapper for Python"""
4+
5+
from paapi5_python_sdk.api.default_api import DefaultApi
6+
from paapi5_python_sdk.condition import Condition
7+
from paapi5_python_sdk.get_items_request import GetItemsRequest
8+
from paapi5_python_sdk.get_items_resource import GetItemsResource
9+
from paapi5_python_sdk.partner_type import PartnerType
10+
from paapi5_python_sdk.rest import ApiException
11+
import time
12+
import logging
13+
14+
15+
# https://webservices.amazon.com/paapi5/documentation/common-request-parameters.html#host-and-region
16+
DOMAINS = {
17+
'AU': 'com.au',
18+
'BR': 'com.br',
19+
'CA': 'ca',
20+
'FR': 'fr',
21+
'DE': 'de',
22+
'IN': 'in',
23+
'IT': 'it',
24+
'JP': 'co.jp',
25+
'MX': 'com.mx',
26+
'ES': 'es',
27+
'TR': 'com.tr',
28+
'AE': 'ae',
29+
'UK': 'co.uk',
30+
'US': 'com'
31+
}
32+
REGIONS = {
33+
'AU': 'us-west-2',
34+
'BR': 'us-east-1',
35+
'CA': 'us-east-1',
36+
'FR': 'eu-west-1',
37+
'DE': 'eu-west-1',
38+
'IN': 'eu-west-1',
39+
'IT': 'eu-west-1',
40+
'JP': 'us-west-2',
41+
'MX': 'us-east-1',
42+
'ES': 'eu-west-1',
43+
'TR': 'eu-west-1',
44+
'AE': 'eu-west-1',
45+
'UK': 'eu-west-1',
46+
'US': 'us-east-1'
47+
}
48+
49+
50+
class Product:
51+
pass
52+
53+
54+
class AmazonAPI:
55+
def __init__(self, key, secret, tag, country, throttling=0.9):
56+
self.key = key
57+
self.secret = secret
58+
self.tag = tag
59+
self.throttling = throttling
60+
self.country = country
61+
self.host = 'webservices.amazon.' + DOMAINS[country]
62+
self.region = REGIONS[country]
63+
self.marketplace = 'www.amazon.' + DOMAINS[country]
64+
self.last_query_time = time.time()
65+
66+
def get_product(self, asin, condition=Condition.NEW):
67+
api = DefaultApi(access_key=self.key,
68+
secret_key=self.secret,
69+
host=self.host,
70+
region=self.region)
71+
72+
product_resources = [
73+
GetItemsResource.BROWSENODEINFO_BROWSENODES,
74+
GetItemsResource.BROWSENODEINFO_BROWSENODES_ANCESTOR,
75+
GetItemsResource.BROWSENODEINFO_BROWSENODES_SALESRANK,
76+
GetItemsResource.BROWSENODEINFO_WEBSITESALESRANK,
77+
GetItemsResource.IMAGES_PRIMARY_SMALL,
78+
GetItemsResource.IMAGES_PRIMARY_MEDIUM,
79+
GetItemsResource.IMAGES_PRIMARY_LARGE,
80+
GetItemsResource.IMAGES_VARIANTS_SMALL,
81+
GetItemsResource.IMAGES_VARIANTS_MEDIUM,
82+
GetItemsResource.IMAGES_VARIANTS_LARGE,
83+
GetItemsResource.ITEMINFO_BYLINEINFO,
84+
GetItemsResource.ITEMINFO_CONTENTINFO,
85+
GetItemsResource.ITEMINFO_CONTENTRATING,
86+
GetItemsResource.ITEMINFO_CLASSIFICATIONS,
87+
GetItemsResource.ITEMINFO_EXTERNALIDS,
88+
GetItemsResource.ITEMINFO_FEATURES,
89+
GetItemsResource.ITEMINFO_MANUFACTUREINFO,
90+
GetItemsResource.ITEMINFO_PRODUCTINFO,
91+
GetItemsResource.ITEMINFO_TECHNICALINFO,
92+
GetItemsResource.ITEMINFO_TITLE,
93+
GetItemsResource.ITEMINFO_TRADEININFO,
94+
GetItemsResource.OFFERS_LISTINGS_AVAILABILITY_MAXORDERQUANTITY,
95+
GetItemsResource.OFFERS_LISTINGS_AVAILABILITY_MESSAGE,
96+
GetItemsResource.OFFERS_LISTINGS_AVAILABILITY_MINORDERQUANTITY,
97+
GetItemsResource.OFFERS_LISTINGS_AVAILABILITY_TYPE,
98+
GetItemsResource.OFFERS_LISTINGS_CONDITION,
99+
GetItemsResource.OFFERS_LISTINGS_CONDITION_SUBCONDITION,
100+
GetItemsResource.OFFERS_LISTINGS_DELIVERYINFO_ISAMAZONFULFILLED,
101+
GetItemsResource.OFFERS_LISTINGS_DELIVERYINFO_ISFREESHIPPINGELIGIBLE,
102+
GetItemsResource.OFFERS_LISTINGS_DELIVERYINFO_ISPRIMEELIGIBLE,
103+
GetItemsResource.OFFERS_LISTINGS_DELIVERYINFO_SHIPPINGCHARGES,
104+
GetItemsResource.OFFERS_LISTINGS_ISBUYBOXWINNER,
105+
GetItemsResource.OFFERS_LISTINGS_LOYALTYPOINTS_POINTS,
106+
GetItemsResource.OFFERS_LISTINGS_MERCHANTINFO,
107+
GetItemsResource.OFFERS_LISTINGS_PRICE,
108+
GetItemsResource.OFFERS_LISTINGS_PROGRAMELIGIBILITY_ISPRIMEEXCLUSIVE,
109+
GetItemsResource.OFFERS_LISTINGS_PROGRAMELIGIBILITY_ISPRIMEPANTRY,
110+
GetItemsResource.OFFERS_LISTINGS_PROMOTIONS,
111+
GetItemsResource.OFFERS_LISTINGS_SAVINGBASIS,
112+
GetItemsResource.OFFERS_SUMMARIES_HIGHESTPRICE,
113+
GetItemsResource.OFFERS_SUMMARIES_LOWESTPRICE,
114+
GetItemsResource.OFFERS_SUMMARIES_OFFERCOUNT,
115+
GetItemsResource.PARENTASIN,
116+
GetItemsResource.RENTALOFFERS_LISTINGS_AVAILABILITY_MAXORDERQUANTITY,
117+
GetItemsResource.RENTALOFFERS_LISTINGS_AVAILABILITY_MESSAGE,
118+
GetItemsResource.RENTALOFFERS_LISTINGS_AVAILABILITY_MINORDERQUANTITY,
119+
GetItemsResource.RENTALOFFERS_LISTINGS_AVAILABILITY_TYPE,
120+
GetItemsResource.RENTALOFFERS_LISTINGS_BASEPRICE,
121+
GetItemsResource.RENTALOFFERS_LISTINGS_CONDITION,
122+
GetItemsResource.RENTALOFFERS_LISTINGS_CONDITION_SUBCONDITION,
123+
GetItemsResource.RENTALOFFERS_LISTINGS_DELIVERYINFO_ISAMAZONFULFILLED,
124+
GetItemsResource.RENTALOFFERS_LISTINGS_DELIVERYINFO_ISFREESHIPPINGELIGIBLE,
125+
GetItemsResource.RENTALOFFERS_LISTINGS_DELIVERYINFO_ISPRIMEELIGIBLE,
126+
GetItemsResource.RENTALOFFERS_LISTINGS_DELIVERYINFO_SHIPPINGCHARGES,
127+
GetItemsResource.RENTALOFFERS_LISTINGS_MERCHANTINFO]
128+
129+
try:
130+
request = GetItemsRequest(partner_tag=self.tag,
131+
partner_type=PartnerType.ASSOCIATES,
132+
marketplace=self.marketplace,
133+
condition=condition,
134+
item_ids=[asin],
135+
resources=product_resources)
136+
except ValueError as exception:
137+
logging.error('Error in forming GetItemsRequest: %s' % (exception))
138+
return
139+
140+
try:
141+
"""Wait before doing the request"""
142+
wait_time = 1 / self.throttling - (time.time() - self.last_query_time)
143+
if wait_time > 0:
144+
time.sleep(wait_time)
145+
self.last_query_time = time.time()
146+
147+
"""Request to the API"""
148+
response = api.get_items(request)
149+
150+
"""Parse the response and create a product"""
151+
if response.items_result is not None:
152+
if len(response.items_result.items) > 0:
153+
item = response.items_result.items[0]
154+
product = Product()
155+
product.asin = asin
156+
157+
try:
158+
product.url = item.detail_page_url
159+
except (NameError, AttributeError):
160+
product.url = None
161+
162+
"""Parse ItemInfo data"""
163+
try:
164+
item_info = item.item_info
165+
except (NameError, AttributeError):
166+
item_info = None
167+
try:
168+
product.title = item_info.title.display_value
169+
except (NameError, AttributeError):
170+
product.title = None
171+
try:
172+
product.release_date = item_info.product_info.release_date.display_value
173+
except (NameError, AttributeError):
174+
product.release_date = None
175+
try:
176+
product.features = item_info.features.display_values
177+
except (NameError, AttributeError):
178+
product.features = None
179+
try:
180+
product.category = item_info.classifications.product_group.display_value
181+
except (NameError, AttributeError):
182+
product.category = None
183+
try:
184+
product.subcategory = item_info.classifications.binding.display_value
185+
except (NameError, AttributeError):
186+
product.subcategory = None
187+
try:
188+
product.brand = item_info.by_line_info.brand.display_value
189+
except (NameError, AttributeError):
190+
product.brand = None
191+
try:
192+
product.manufacturer = item_info.by_line_info.manufacturer.display_value
193+
except (NameError, AttributeError):
194+
product.manufacturer = None
195+
196+
"""Parse Images data"""
197+
try:
198+
images = item.images
199+
except (NameError, AttributeError):
200+
images = None
201+
try:
202+
product.image_large = images.primary.large.url.replace('.jpg',
203+
'._AC_.jpg')
204+
except (NameError, AttributeError):
205+
product.image_large = None
206+
try:
207+
product.image_medium = images.primary.medium.url.replace('_SL', '_AC')
208+
except (NameError, AttributeError):
209+
product.image_medium = None
210+
try:
211+
product.image_small = images.primary.small.url.replace('_SL', '_AC')
212+
except (NameError, AttributeError):
213+
product.image_small = None
214+
try:
215+
product.image_variants = []
216+
for variant in images.variants:
217+
try:
218+
product.image_variants.append(
219+
variant.large.url.replace('.jpg', '._AC_.jpg'))
220+
except (NameError, AttributeError):
221+
pass
222+
if not product.image_variants:
223+
product.image_variants = None
224+
except (NameError, AttributeError):
225+
product.image_variants = None
226+
227+
"""Parse Offers Listings data"""
228+
product.prices = Product()
229+
try:
230+
listings = item.offers.listings[0]
231+
except (NameError, AttributeError):
232+
listings = None
233+
try:
234+
product.prices.availability = listings.availability.message
235+
except (NameError, AttributeError):
236+
product.prices.availability = None
237+
try:
238+
product.prices.price = listings.price.amount
239+
except (NameError, AttributeError):
240+
product.prices.price = None
241+
try:
242+
product.prices.pvp = listings.saving_basis.amount
243+
except (NameError, AttributeError):
244+
product.prices.pvp = None
245+
246+
"""Parse Offers Summaries data"""
247+
product.offers = Product()
248+
try:
249+
product.offers = item.offers.summaries
250+
except (NameError, AttributeError):
251+
product.offers = None
252+
253+
return product
254+
255+
else:
256+
return None
257+
258+
except Exception as exception:
259+
logging.error(str(exception))
260+
return None

0 commit comments

Comments
 (0)