diff --git a/myprotein.py b/myprotein.py index 3bb0156..fc979af 100644 --- a/myprotein.py +++ b/myprotein.py @@ -37,7 +37,6 @@ class Option(NamedTuple): id: int name: str - value: str @dataclass @@ -58,6 +57,7 @@ class ProductNotExistError(Exception): '10852500': ProductInformation('impact_whey', 'Unflavored', '2.2 lb', 0.0), '11464969': ProductInformation('whey_pouch', 'Vanilla', '0.55 lb', 0.0), '10852482': ProductInformation('whey_isolate', 'Unflavored', '2.2 lb', 0.0), + '11181407': ProductInformation('impact_blend', 'Unflavored', '2.2 lb', 0.0), '11111095': ProductInformation('iospro', 'Unflavored', '1.1 lb', 0.0), # Creatine '10852407': ProductInformation('creatine_monohydrate', 'Unflavored', '2.2 lb', 0.0), @@ -189,21 +189,14 @@ def get_price_data(product_category_id: str) -> Dict[str, float]: def get_all_products(product_id: str) -> Tuple[List[Option], List[Option]]: """Query endpoint to get possible product variations (size and flavour)""" - url = f'https://us.myprotein.com/variations.json?productId={product_id}' - response = addict.Dict(requests.get(url).json()) - flavours = [ - Option(**flavour) - for variation in response.variations - for flavour in variation.options - if variation.variation == 'Flavour' - ] - - sizes = [ - Option(**size) - for variation in response.variations - for size in variation.options - if variation.variation == 'Amount' - ] + response = requests.get(f'https://us.myprotein.com/{product_id}.html') + dom = bs4.BeautifulSoup(response.text, 'html.parser') + + products = dom.select('#athena-product-variation-dropdown-5 option') + flavours = [Option(int(i['value']), i.text.strip()) for i in products] + + sizes = dom.select('.athenaProductVariations_list button') + sizes = [Option(int(i['data-option-id']), name=i.text.strip()) for i in sizes] return flavours, sizes diff --git a/myprotein_test.py b/myprotein_test.py index 7508b48..117cb0e 100644 --- a/myprotein_test.py +++ b/myprotein_test.py @@ -1,6 +1,5 @@ # Disable redefined function name warning because that's how pytest fixtures work by default # pylint: disable=redefined-outer-name -import json from typing import Any from typing import Iterator from unittest import mock @@ -123,44 +122,56 @@ def test_get_product_information_not_found() -> None: def test_get_all_products(mocked_responses: Any) -> None: - response = { - 'variations': [ - { - 'id': 100, - 'variation': 'Flavour', - 'options': [{'id': 111, 'name': 'flavour_name', 'value': 'flavour_value'}], - }, - { - 'id': 200, - 'variation': 'Amount', - 'options': [ - {'id': 211, 'name': 'size_name1', 'value': 'size_value1'}, - {'id': 222, 'name': 'size_name2', 'value': 'size_value2'}, - ], - }, - ] - } - + # This is a mocked snippet and apsires to demonstrate the rough structure of page + body = ''' + +
+
+
+
+ +
+
+
+
+
+
    +
  • + +
  • +
  • + +
  • +
+
+
+
+
+
+ + ''' product_category_id = '12345' - mocked_responses.add( - responses.GET, - f'https://us.myprotein.com/variations.json?productId={product_category_id}', - body=json.dumps(response), - ) + mocked_responses.add(responses.GET, f'https://us.myprotein.com/{product_category_id}.html', body=body) flavours, sizes = myprotein.get_all_products(product_category_id) assert len(flavours) == 1 - assert flavours[0] == myprotein.Option(111, 'flavour_name', 'flavour_value') + assert flavours[0] == myprotein.Option(111, 'flavour_name') - TestCase().assertCountEqual( - sizes, [myprotein.Option(222, 'size_name2', 'size_value2'), myprotein.Option(211, 'size_name1', 'size_value1')] - ) + TestCase().assertCountEqual(sizes, [myprotein.Option(222, 'size_name2'), myprotein.Option(211, 'size_name1')]) def test_resolve_options_to_product_id(mock_responses_with_default_product_information: Any) -> None: - flavour = myprotein.Option(111, 'name', 'value') - size = myprotein.Option(222, 'name', 'value') + flavour = myprotein.Option(111, 'name') + size = myprotein.Option(222, 'name') # impact whey product_category_id = '10852500' @@ -245,8 +256,8 @@ def test_resolve_options_to_product_id_default_product(mock_responses_with_defau product_category_id = '10852500' # Queried option matches the default product - flavour = myprotein.Option(111, 'Unflavored', 'Unflavored') - size = myprotein.Option(222, '2.2 lb', '2.2 lb') + flavour = myprotein.Option(111, 'Unflavored') + size = myprotein.Option(222, '2.2 lb') product_response = '''