从网站上刮取隐藏变量(Bs4)

时间:2018-05-03 09:17:05

标签: python-3.x web-scraping beautifulsoup

我正在努力学习如何抓取网站。我使用的是Python3和BS4。

我遇到了一个特定的问题。 例如:http://www2.hm.com/en_in/productpage.0648256001.html

我无法刮掉"尺寸"可在下拉菜单中找到它们是否已售罄,在上面的链接中。我浏览了整个源代码,但无法弄清楚数据存在于哪个标签下。我猜它一定是一个隐藏的变量或什么?

1 个答案:

答案 0 :(得分:3)

好的,所以我跟踪了网站提出的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对象对我来说似乎是不可能的(如果我&#39;我错了)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属性与&#34;产品变体&#34;的data-articlecode属性相匹配:

<li class="list-item">
    <a title="Light beige/Patterned" data-color="Light beige/Patterned"
       data-articlecode="0648256001">
        ...
    </a>
</li>

我鼓励您自己实施,但我会在晚上/明天尝试对其进行编码以完成答案。但是,该网站使用JavaScript呈现,并且在对GET请求的响应中,您不会获得您在DevTools的Elements选项卡中看到的整个HTML。您可以使用Selenium来做到这一点,但就个人而言,我使用Requests-HTML