【问题标题】:Trying to webscrape the price from an Amazon page using the CSS selector and Python/BeautifulSoup尝试使用 CSS 选择器和 Python/BeautifulSoup 从亚马逊页面抓取价格
【发布时间】:2020-09-10 16:15:33
【问题描述】:

我正在尝试在 Udemy 课程“使用 Python 自动化无聊的东西”中了解网络抓取。

我正在尝试将 Python 与 requests 和 BeautifulSoup 模块以及 CSS 选择器一起使用来返回给定亚马逊商品的价格。

我可以在课程中看到很多人无法让这个工作,所以我怀疑亚马逊网页发生了一些变化。但是,我也尝试过其他一些网页,例如currys.co.uk 似乎也无法让它在那里工作。

BeautifulSoup 似乎可以很好地解析所有内容,我认为问题不存在,只是当我尝试从 Chrome 获取 CSS 选择器时,一切都不起作用。

例如,在这个网页上:

https://www.amazon.com/Automate-Boring-Stuff-Python-Programming/dp/1593275994

如果我右键点击价格,点击“检查”,然后复制->复制选择器,我得到

#unqualifiedBuyBox > div > div.a-text-center.a-spacing-mini > span

我很确定这不是我正在寻找的 CSS 选择器,将它放入我的 Python 代码不会返回价格。

我在这里做错了吗?

感谢您的帮助。

【问题讨论】:

  • 许多页面使用 JavaScript 向页面添加元素,但 BeautifulSoup 无法运行 JavaScript - 因此通常无法获取元素。然后你可能需要 Selenium 来控制可以运行 JavaScript 的网络浏览器。或者您可以尝试在 Firefox/Chrome 中使用 DevTools(选项卡:网络,过滤器:XHR)来查找 JavaScript 用于读取数据的 url,然后您可以使用 requests 从该 url 获取数据 - 通常您会获取数据JSON 格式,所以你不需要BeautifulSoup
  • 顺便说一句:关闭网页浏览器中的 JavaScript 并重新加载页面以查看 BeautifulSoup 可以从服务器获取什么。
  • 一些服务器为不同的设备发送不同的 HTML - 手机、平板电脑、台式机 - 所以使用正确的标题 User-Agent 可能很重要。其他服务器可以识别您运行脚本并发送带有警告的页面并阻止您 - 因此您可以将 HTML 保存到页面并显示在 Web 浏览器中以查看您得到的结果。
  • 除了亚马逊想要阻止爬虫之外,您还缺少# 符号。在 chrome 控制台上试试这个:$("#unqualifiedBuyBox > div > div.a-text-center.a-spacing-mini > span").innerText
  • @BalajiAmbresh OP 在 CSS 选择器中已经有 #,但 OP 的文本格式不正确,Stackoverflow 使用 # 将其显示为粗体文本 :)

标签: python css google-chrome web-scraping beautifulsoup


【解决方案1】:

如果没有看到您的代码,很难确定,但以下是我在自己解决此问题时必须解决的一些可能的问题:

1.您的请求正在触发亚马逊的验证码

您可以在使用 BeautifulSoup 解析页面后查看您的汤来确认这一点:

soup = bs4.BeautifulSoup(res.text, 'html.parser')
print(soup)

如果亚马逊检测到了爬虫,生成的文件将只有几百行(验证码页面),而不是 10,000 多行(产品页面)。要绕过它,您可以在请求标头中设置 User-AgentAccept-Language。示例:

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36',
    'Accept-Language': 'en-US'
    }
res = requests.get('https://www.amazon.com/dp/1593275994', headers=headers)

您可以获取与您的环境匹配的用户代理配置文件here;对于接受语言,最好使其与您的 IP 地址保持一致,以避免检测到类似机器人的行为。您可以在IANA Language Subtag Registry 中查看完整列表。

2。录制 Udemy 视频后,Chrome 的复制 CSS 路径功能发生了变化

Copy CSS path 现在变成了Copy selector。要访问它,请右键单击 Elements Window > Copy > Copy selector 中的元素。

3.元素的 CSS 路径因产品可用性而异

亚马逊如何显示商品价格的页面样式可能会有所不同,具体取决于商品是新品还是二手商品,以及该商品是由亚马逊直接发货还是仅通过亚马逊商城提供。

在撰写本文时,您共享的产品链接的正确 CSS 选择器是 #unqualified-buybox-olp > div > span,因此您可以使用

elems = soup.select('#unqualified-buybox-olp > div > span')

【讨论】:

    【解决方案2】:

    编辑:2021.07.29

    似乎示例页面更改了结构并且类#unqualifiedBuyBox 不存在。


    原始答案:

    要获取数据,我需要两件事:

    1. headers User-Agent, Accept-Language 获取带有数据的 HTML,而不是机器人/脚本的消息

    2. 使用解析器 lxml 而不是 html.parser 来查找元素(解析器以不同的方式工作)

    但是,如果您将多次运行代码并有短暂的延迟,那么即使这样也可能行不通。


    import requests
    from bs4 import BeautifulSoup as BS
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/76.0',
        'Accept-Language': 'en-US;q=0.7,en;q=0.3',
    #    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    #    'Accept-Encoding': 'gzip, deflate, br',
    }
    
    url = 'https://www.amazon.com/Automate-Boring-Stuff-Python-Programming/dp/1593275994'
    r = requests.get(url, headers=headers)
    
    #soup = BS(r.text, 'html.parser')
    soup = BS(r.text, 'lxml')
    
    all_items = soup.select('#unqualifiedBuyBox > div > div.a-text-center.a-spacing-mini > span')
    for item in all_items:
        print(item.text)
    

    编辑:2021.07.29

    最初的答案是一年前,现在示例页面没有价格,其他页面使用不同的类和 id - 所以现在它需要不同的选择器。

    import requests
    from bs4 import BeautifulSoup as BS
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/76.0',
        'Accept-Language': 'en-US;q=0.7,en;q=0.3',
    #    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    #    'Accept-Encoding': 'gzip, deflate, br',
    }
    
    #url = 'https://www.amazon.com/Automate-Boring-Stuff-Python-Programming/dp/1593275994'
    url = 'https://www.amazon.com/Automate-Boring-Stuff-Python-2nd/dp/1593279922/'
    r = requests.get(url, headers=headers)
    
    #soup = BS(r.text, 'html.parser')
    soup = BS(r.text, 'lxml')
    
    all_items = soup.select('#newBuyBoxPrice')
    for item in all_items:
        print(item.text)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-07
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 2015-11-03
      • 2014-12-06
      相关资源
      最近更新 更多