Хорошо, я отследил XHR-запросы, которые делает веб-сайт, и написал код ниже. По сути, он использует Selenium
, чтобы получить значение переменной productArticleDetails
и URL-адрес конечной точки доступности (я мог бы жестко закодировать ее, но нашел переменную, в которой она находится, поэтому почему бы не использовать ее) .
from itertools import chain
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
url = 'http://www2.hm.com/en_in/productpage.0648256002.html'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'lxml')
browser = webdriver.Chrome()
browser.get(url)
details = browser.execute_script('return productArticleDetails;')
availability_url = browser.execute_script('return hm.options.product.productAvailabilityServiceUrl;')
browser.quit()
variants = {} # e.g one product can be available in different colors
for key, value in details.items():
# there is a lot of information in the details, not only product variants
try:
if 'whitePrice' in value:
variants[key] = value
except AttributeError:
pass
# 'http://www2.hm.com/en_in/getAvailability?variants=0648256001,0648256002,0648256003,0648256006,0648256007,0648256008'
payload = {'variants': ','.join(variants.keys())}
r = requests.get(urljoin(url, availability_url), params=payload)
available_sizes = r.json()['availability']
# r.json() contains:
# availability: ["0648256001001", "0648256001002", "0648256001007",…]
# fewPieceLeft: []
sizes = chain.from_iterable(variant['sizes'] for variant in variants.values())
for size in sizes:
availability = size['sizeCode'] in available_sizes
size['available'] = availability # True/False, feel free to implement handling "fewPieceLeft"
# Output
for variant in variants.values():
print(f'Variant: {variant["name"]}') # color in that case
print('\tsizes:')
for size in variant['sizes']:
print(f'\t\t{size["name"]} -> {"Available" if size["available"] else "Sold out"}')
Выход:
Variant: Light beige/Patterned
sizes:
32 -> Available
34 -> Available
36 -> Sold out
...
Variant: Orange
sizes:
32 -> Available
...
Преимущество этого подхода заключается в том, что вы получаете доступ ко многим деталям, таким как 'whitePrice': 'Rs. 1,299',
, 'careInstructions': ['Machine wash at 30°']
, 'composition': ['Viscose 100%']
, описание и некоторые другие. Вы можете посмотреть сами:
import pprint
pprint.pprint(variants)
Недостатком является то, что вам нужно использовать Selenium и загрузить драйвер, но, если честно, я использовал Selenium только для получения переменных, поскольку извлечение этого вложенного объекта JS с помощью регулярных выражений мне кажется невозможным (поправьте меня, если я ошибаюсь) ) и browser.execute_script('return productArticleDetails;')
очень ясно и кратко.
<ч />
Нет скрытых переменных, и можно получить размеры с помощью BeautifulSoup
, каждый размер равен <li>
:
<li class="item" data-code="0648256001002">
<div class="picker-option"><button type="button" class="option"><span class="value">34</span></button></div>
</li>
Необходимо сопоставить атрибут data-code
размера с атрибутом data-articlecode
«варианта продукта»:
<li class="list-item">
<a title="Light beige/Patterned" data-color="Light beige/Patterned"
data-articlecode="0648256001">
...
</a>
</li>
Я призываю вас реализовать это самостоятельно, но я постараюсь написать код вечером / завтра, чтобы завершить ответ. Однако веб-сайт отображается с использованием JavaScript, и в ответ на запрос GET вы не получите весь HTML-код, который вы видите на вкладке «Элементы» в DevTools. Вы можете использовать Selenium для этого, но лично я бы использовал Requests-HTML