【问题标题】:Intermittent BeautifulSoup with Amazon Book ISBNAmazon Book ISBN 的间歇 BeautifulSoup
【发布时间】:2020-12-11 22:42:53
【问题描述】:

我正在尝试收集有关亚马逊上某些书籍的一些信息,但我遇到了一个我无法理解的奇怪故障错误。起初我以为是亚马逊阻止了我的连接,但后来我注意到请求有“200 OK”,并且它具有相应页面的真实 HTML 内容。

我们以这本书为例:https://www.amazon.co.uk/All-Rage-Cara-Hunter/dp/0241985110

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}

url = 'https://www.amazon.co.uk/All-Rage-Cara-Hunter/dp/0241985110/ref=sr_1_1?crid=2PPCQEJD706VY&dchild=1&keywords=books+bestsellers+2020+paperback&qid=1598132071&sprefix=book%2Caps%2C234&sr=8-1'

response = requests.get(url, headers=headers)

soup = BeautifulSoup(response.content, features="lxml")

price = {}

if soup.select("#buyBoxInner > ul > li > span > .a-text-strike") != []:
    price["regular_price"] = float(
        soup.select("#buyBoxInner > ul > li > span > .a-text-strike")[0].string[1:].replace(",", "."))
    price["promo_price"] = float(soup.select(".offer-price")[0].string[1:].replace(",", "."))
else:
    price["regular_price"] = float(soup.select(".offer-price")[0].string[1:].replace(",", "."))
price["currency"] = soup.select(".offer-price")[0].string[0]

这部分工作正常,我可以获得正常价格和促销价格(如果存在),甚至是货币。但是当我这样做时:

isbn = soup.select("td.bucket > .content > ul > li")[4].contents[1].string.strip().replace("-", "")

我得到“IndexError:列表索引超出范围”。但是如果我调试代码,内容其实是有的!

这是 BeautifulSoup 的错误吗?请求响应是否太长?

【问题讨论】:

  • soup.select("td.bucket > .content > ul > li")[4] 抛出错误还是contents[1]
  • @sintribu soup.select("td.bucket > .content > ul > li")[4]
  • 我不知道这对你有什么帮助,但是当我运行这段代码时,它对我来说运行良好。我只需要在顶部添加几个导入,在底部添加一个 print(isbn),然后我得到 9780241985113 的输出
  • 它有时对我有用,但对其他人无效。网络抓取是一件奇怪的事情???
  • 哇!同样在这里。 4 次中有 3 次对我有用。

标签: python beautifulsoup python-requests


【解决方案1】:

亚马逊似乎返回了两个版本的页面。一个是<td class="bucket">,一个是几个<span> 标签。此脚本尝试从两者中提取 ISBN:

import requests
from bs4 import BeautifulSoup


headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}

url = 'https://www.amazon.co.uk/All-Rage-Cara-Hunter/dp/0241985110'
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, features="lxml")

isbn_10 = soup.select_one('span.a-text-bold:contains("ISBN-10"), b:contains("ISBN-10")').find_parent().text
isbn_13 = soup.select_one('span.a-text-bold:contains("ISBN-13"), b:contains("ISBN-13")').find_parent().text

print(isbn_10.split(':')[-1].strip())
print(isbn_13.split(':')[-1].strip())

打印:

0241985110
978-0241985113

【讨论】:

  • 哇。不错的收获,以及出色的解决方案。你显然知道你的汤。你知道为什么亚马逊会返回两个不同的页面吗?我想知道这是否与推出尚未(或尚未)进入所有服务器的新版本页面有关。
  • @Steve 也许他们对同一页面的两个版本或不同版本的服务器软件进行 A/B 测试……或者他们想让机器人更难抓取信息。
  • @AndrejKesely 非常感谢!有效。还有一个问题。价格选择器好吗?我用 50 多个 URL 的列表运行它,它给出了相同的错误,但价格昂贵。你怎么看?
  • @MiguelSantana 我认为您正在从服务器获取验证码页面。经过几次请求,我也开始得到它。
  • @AndrejKesely 你认为如果我创建一个 requests.session 我可以绕过它吗?
【解决方案2】:

我希望我对问题有一个解释,但您的解决方案是将您的代码包装在这样的函数中:

def scrape():
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}

    url = 'https://www.amazon.co.uk/All-Rage-Cara-Hunter/dp/0241985110/ref=sr_1_1?crid=2PPCQEJD706VY&dchild=1&keywords=books+bestsellers+2020+paperback&qid=1598132071&sprefix=book%2Caps%2C234&sr=8-1'

    response = requests.get(url, headers=headers)

    soup = BeautifulSoup(response.content, features="lxml")

    price = {}

    if soup.select("#buyBoxInner > ul > li > span > .a-text-strike") != []:
        price["regular_price"] = float(
            soup.select("#buyBoxInner > ul > li > span > .a-text-strike")[0].string[1:].replace(",", "."))
        price["promo_price"] = float(soup.select(".offer-price")[0].string[1:].replace(",", "."))
    else:
        price["regular_price"] = float(soup.select(".offer-price")[0].string[1:].replace(",", "."))
    price["currency"] = soup.select(".offer-price")[0].string[0]


    #ADD THIS FEATURE TO YOUR CODE
    isbn = soup.select("td.bucket > .content > ul > li")
    if not isbn:
        scrape()


    isbn = isbn[4].contents[1].string.strip().replace("-", "")

如果它失败了,它会再次调用自己。您可能想要重构它,使其只发出一次请求。

【讨论】:

  • 感谢您的意见,但我实际上已经尝试过类似的方法并且它保持不变。有时它总是失败。
猜你喜欢
  • 1970-01-01
  • 2010-12-27
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 2010-10-14
  • 2011-06-03
  • 1970-01-01
  • 2021-07-13
相关资源
最近更新 更多