Skip to content

Commit 641a4fa

Browse files
authored
Merge pull request #27 from sergioteula/dev_browsenode
Added browse node functionality, removed 10 pages limit and solved unnecessary API call
2 parents 9880acf + 7e2d54f commit 641a4fa

File tree

6 files changed

+160
-11
lines changed

6 files changed

+160
-11
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Features
1515
* Object oriented interface for simple usage.
1616
* Get information about a product through its ASIN or URL.
1717
* Get item variations or search for products on Amazon.
18+
* Get browse nodes information.
1819
* Get multiple results at once without the 10 items limitation from Amazon.
1920
* Configurable throttling to avoid requests exceptions.
2021
* Support for [all available countries](https://github.com/sergioteula/python-amazon-paapi/blob/master/amazon/paapi.py#L31).
@@ -58,6 +59,10 @@ Usage guide
5859
product = amazon.search_products(item_count=25, keywords='speaker')
5960
print(product[14].url)
6061

62+
**Get browse node information:**
63+
64+
node = amazon.get_browsenodes(browse_nodes=browsenodes_list)
65+
6166
**Get the ASIN from a URL:**
6267

6368
from amazon.tools import get_asin
@@ -72,6 +77,11 @@ Throttling value must be `greater than 0` or `False` to disable it. This value t
7277

7378
Changelog
7479
-------------
80+
Version 3.2.0
81+
- Added new method for getting browse nodes information.
82+
- Removed the 10 pages limit on search_products and get_variations methods.
83+
- Solved unnecessary API call on search_products and get_variations methods.
84+
7585
Version 3.1.0
7686
- Added paapi5-python-sdk and removed amightygirl.paapi5-python-sdk.
7787
- Improved throttling and now possible to disable it.

amazon/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Amazon Product Advertising API wrapper for Python"""
22

3-
__version__ = '3.1.0'
3+
__version__ = '3.2.0'
44
__author__ = 'Sergio Abad'

amazon/constant.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from paapi5_python_sdk.get_items_resource import GetItemsResource
44
from paapi5_python_sdk.search_items_resource import SearchItemsResource
55
from paapi5_python_sdk.get_variations_resource import GetVariationsResource
6+
from paapi5_python_sdk.get_browse_nodes_resource import GetBrowseNodesResource
67
from paapi5_python_sdk.condition import Condition
78

89
"""Available regions for the Amazon API."""
@@ -228,3 +229,9 @@
228229
GetVariationsResource.VARIATIONSUMMARY_PRICE_LOWESTPRICE,
229230
GetVariationsResource.VARIATIONSUMMARY_VARIATIONDIMENSION
230231
]
232+
233+
"""Browse Node resources to get from Amazon API."""
234+
BROWSE_RESOURCES = [
235+
GetBrowseNodesResource.ANCESTOR,
236+
GetBrowseNodesResource.CHILDREN
237+
]

amazon/paapi.py

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
from paapi5_python_sdk.get_items_request import GetItemsRequest
1010
from paapi5_python_sdk.search_items_request import SearchItemsRequest
1111
from paapi5_python_sdk.get_variations_request import GetVariationsRequest
12+
from paapi5_python_sdk.get_browse_nodes_request import GetBrowseNodesRequest
1213
from paapi5_python_sdk.partner_type import PartnerType
1314
from paapi5_python_sdk.rest import ApiException
1415

1516
from amazon.constant import DOMAINS, REGIONS, CONDITION
1617
from amazon.constant import PRODUCT_RESOURCES, SEARCH_RESOURCES, VARIATION_RESOURCES
18+
from amazon.constant import BROWSE_RESOURCES
1719
from amazon.exception import AmazonException
18-
from amazon.parse import parse_product
20+
from amazon.parse import parse_product, AmazonBrowseNode, parse_browsenode
1921
from amazon.tools import get_asin, chunks
2022

2123
import time
@@ -226,8 +228,8 @@ def search_products(self, item_count=10, item_page=1, items_per_page=10, keyword
226228
raise AmazonException('ValueError', 'Arg items_per_page should be between 1 and 10')
227229
if item_count > 100 or item_count < 1:
228230
raise AmazonException('ValueError', 'Arg item_count should be between 1 and 100')
229-
if item_page > 10 or item_page < 1:
230-
raise AmazonException('ValueError', 'Arg item_page should be between 1 and 10')
231+
if item_page < 1:
232+
raise AmazonException('ValueError', 'Arg item_page should be 1 or higher')
231233
if not keywords and not actor and not artist and not author and not brand and not title:
232234
raise AmazonException('ValueError', 'At least one of the following args must be '
233235
'provided: keywords, actor, artist, author, brand,'
@@ -284,6 +286,8 @@ def search_products(self, item_count=10, item_page=1, items_per_page=10, keyword
284286
results.append(parse_product(item))
285287
if len(results) >= item_count:
286288
break
289+
if len(response.search_result.items) < items_per_page:
290+
break
287291
else:
288292
break
289293
if response.errors is not None:
@@ -293,8 +297,6 @@ def search_products(self, item_count=10, item_page=1, items_per_page=10, keyword
293297
break
294298
raise AmazonException('ResponseError', e)
295299
item_page += 1
296-
if item_page > 10:
297-
break
298300

299301
if results:
300302
return results
@@ -331,8 +333,8 @@ def get_variations(self, asin, item_count=10, item_page=1, items_per_page=10, co
331333
raise AmazonException('ValueError', 'Arg items_per_page should be between 1 and 10')
332334
if item_count > 100 or item_count < 1:
333335
raise AmazonException('ValueError', 'Arg item_count should be between 1 and 100')
334-
if item_page > 10 or item_page < 1:
335-
raise AmazonException('ValueError', 'Arg item_page should be between 1 and 10')
336+
if item_page < 1:
337+
raise AmazonException('ValueError', 'Arg item_page should be 1 or higher')
336338

337339
results = []
338340
while len(results) < item_count:
@@ -373,17 +375,70 @@ def get_variations(self, asin, item_count=10, item_page=1, items_per_page=10, co
373375
results.append(parse_product(item))
374376
if len(results) >= item_count:
375377
break
378+
if len(response.variations_result.items) < items_per_page:
379+
break
376380
else:
377381
break
378382
if response.errors is not None:
379383
raise AmazonException(response.errors[0].code, response.errors[0].message)
380384
except Exception as e:
381385
raise AmazonException('ResponseError', e)
382386
item_page += 1
383-
if item_page > 10:
384-
break
385387

386388
if results:
387389
return results
388390
else:
389391
return None
392+
393+
def get_browsenodes(self, browse_nodes, async_req=False):
394+
"""Get browse nodes information from Amazon.
395+
396+
Args:
397+
browse_nodes (list): List of strings containing the browse node ids.
398+
async_req (bool, optional): Specify if a thread should be created to
399+
run the request. Defaults to False.
400+
401+
Returns:
402+
dict: A dictionary containing the browse node information.
403+
"""
404+
405+
if isinstance(browse_nodes, list) is False:
406+
raise Exception('Browse nodes parameter should be a list')
407+
elif not browse_nodes:
408+
raise Exception('Browse nodes parameter can\'t be empty')
409+
410+
try:
411+
request = GetBrowseNodesRequest(
412+
partner_tag=self.tag,
413+
partner_type=PartnerType.ASSOCIATES,
414+
marketplace=self.marketplace,
415+
browse_node_ids=browse_nodes,
416+
languages_of_preference=None,
417+
resources=BROWSE_RESOURCES)
418+
except ValueError as e:
419+
raise AmazonException("ValueError", e)
420+
421+
try:
422+
self._throttle()
423+
if async_req:
424+
thread = self.api.get_browse_nodes(request, async_req=True)
425+
response = thread.get()
426+
else:
427+
response = self.api.get_browse_nodes(request)
428+
except ApiException as e:
429+
raise AmazonException('ApiException', e)
430+
431+
try:
432+
if response.browse_nodes_result is not None:
433+
res = [AmazonBrowseNode(item) for item in response.browse_nodes_result.browse_nodes]
434+
return parse_browsenode(res)
435+
if response.errors is not None:
436+
raise AmazonException(response.errors[0].code, response.errors[0].message)
437+
except TypeError as e:
438+
raise AmazonException("TypeError", e)
439+
except ValueError as e:
440+
raise AmazonException(ValueError, e)
441+
except AmazonException as e:
442+
raise AmazonException(e.status, e.reason)
443+
except Exception as e:
444+
raise AmazonException("General", e)

amazon/parse.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,83 @@ class Class:
66
pass
77

88

9+
class AmazonBrowseNode():
10+
swagger_types = {
11+
'ancestor': 'BrowseNodeAncestor',
12+
'children': 'BrowseNodeChildren',
13+
'context_free_name': 'str',
14+
'display_name': 'str',
15+
'id': 'str',
16+
'is_root': 'bool',
17+
'sales_rank': 'int'
18+
}
19+
20+
def __init__(self, node):
21+
self.ancestor = node.ancestor
22+
self.children = node.children
23+
self.context_free_name = node.context_free_name
24+
self.display_name = node.display_name
25+
self.id = node.id
26+
self.is_root = node.is_root
27+
self.sales_rank = node.sales_rank
28+
29+
def to_dict(self):
30+
result = {}
31+
32+
for attr, _ in six.iteritems(self.swagger_types):
33+
value = getattr(self, attr)
34+
if isinstance(value, list):
35+
result[attr] = list(map(
36+
lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
37+
value
38+
))
39+
elif hasattr(value, "to_dict"):
40+
result[attr] = value.to_dict()
41+
elif isinstance(value, dict):
42+
result[attr] = dict(map(
43+
lambda item: (item[0], item[1].to_dict())
44+
if hasattr(item[1], "to_dict") else item,
45+
value.items()
46+
))
47+
else:
48+
result[attr] = value
49+
if issubclass(BrowseNode, dict):
50+
for key, value in self.items():
51+
result[key] = value
52+
53+
return result
54+
55+
def to_str(self):
56+
return pprint.pformat(self.to_dict())
57+
58+
def __repr__(self):
59+
return self.to_str()
60+
61+
def __eq__(self, other):
62+
if not isinstance(other, BrowseNode):
63+
return False
64+
65+
return self.__dict__ == other.__dict__
66+
67+
def __ne__(self, other):
68+
return not self == other
69+
70+
71+
def parse_browsenode(browse_nodes_response):
72+
"""Parse browse node data and creates a dict.
73+
74+
Args:
75+
browse_nodes_response (list): List of browse nodes responses.
76+
77+
Returns:
78+
dict: Dict with browse node information.
79+
"""
80+
mapped_response = {}
81+
for browse_node in browse_nodes_response:
82+
mapped_response[browse_node.id] = browse_node
83+
return mapped_response
84+
85+
986
def parse_product(item):
1087
"""Parse item data and creates product instance.
1188

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name='python-amazon-paapi',
8-
version='3.1.0',
8+
version='3.2.0',
99
author='Sergio Abad',
1010
author_email='sergio.abad@bytelix.com',
1111
description='Amazon Product Advertising API 5.0 wrapper for Python',

0 commit comments

Comments
 (0)