BeautifulSoup 有时会出现异常

Posted

技术标签:

【中文标题】BeautifulSoup 有时会出现异常【英文标题】:BeautifulSoup sometimes gives exceptions 【发布时间】:2015-02-13 18:01:30 【问题描述】:

奇怪的是,有时 BeautifulSoup 对象确实提供了所需的数据,但有时我会收到类似或 listindex errorout of rangenonetype object does not have attribute findNext() 的错误,这是嵌套在其他元素中的数据。

这是代码:

url = 'http://www.computerstore.nl/product/470130/category-208983/asrock-z97-extreme6.html'
source_code = requests.get(url)
plain_text = source_code.text
soup = BeautifulSoup(plain_text)

a = soup.find(text=('Socket')).find_next('dd').string

print(a)

【问题讨论】:

【参考方案1】:

实际问题是单元格值并不总是Socket有时被制表符或空格包围。不要检查确切的text 匹配,而是传递compiled regular expression pattern:

import re

soup.find(text=re.compile('Socket')).find_next('dd').get_text(strip=True)

总是打印1150


解释我使用过的“有时”这个词(感谢@carpetsmoker 在 cmets 中的最初提议):

如果您打开页面,然后清理 cookie 并刷新页面,您可能会看到同一页面的两种不同外观:

如您所见,页面上的块排列方式不同。因此,同一个页面有两种不同的外观和 HTML 源代码 - 您看到的是 AB-testing 技术:

在营销和商业智能中,A/B 测试是 有两个变体 A 和 B 的随机实验,它们是 对照实验中的对照和处理。它是一种形式 使用两种变体的统计假设检验导致 技术术语,双样本假设检验,用于以下领域 统计数据。

换句话说,他们正在尝试产品页面并收集统计数据,例如点击率、销售数量等。


仅供参考,这是我目前得到的工作代码:

import re

from bs4 import BeautifulSoup
import requests

session = requests.Session()
headers = 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36'
session.get('http://www.computerstore.nl', headers=headers)

response = session.get('http://www.computerstore.nl/product/470130/category-208983/asrock-z97-extreme6.html', headers=headers)
soup = BeautifulSoup(response.content)
print(soup.find(text=re.compile('Socket')).find_next('dd').get_text(strip=True))

【讨论】:

"反网页抓取技术";不,这似乎是 AB 测试;如果您在浏览器中禁用 cookie,并打开几个选项卡,您将在某些页面中获得不同的 HTML 页面 :-) 我试图通过回显 cookie 来保持相同的页面布局,但似乎没有一种明显的方法可以获取您实际查看的页面,因此您被困在同样的问题,但这很丑:-/ @Carpetsmoker 我已经更新了答案——显然是 AB 测试。再次感谢您的提示。 好吧,你说得对,它现在可以工作的套接字,谢谢,但我也有这个问题,因为另外两个数据 'Format Moederbord' 和 'Chipset' 。如果我使用你说的代码而不是'Socket''Formaat Moederbord'或'Chipset',它会再次出现问题,我该如何解决这个问题。 @user3660293 好吧,它适用于Chipset,就像它适用于Socket 一样,但Formaat Moederbord - 这是一个不同的故事,这是你可以找到的方法它(适用于 A 和 B 情况)print(soup.find(text=re.compile('Formaat moederbord')).find_parent(['td', 'dt']).find_next(['td', 'dd']).find_next(['td', 'dd']).get_text(strip=True)).【参考方案2】:

我对您的代码进行了建议更改:

url = 'http://www.computerstore.nl/product/470130/category-208983/asrock-z97-extreme6.html'
source_code = requests.get(url)
plain_text = source_code.text
soup = BeautifulSoup(plain_text)

if soup.find(text=('Socket')):
   a = soup.find(text=('Socket')).find_next('dd').string
else:
   # Display some error info, and/or do some error logging
   print "error"

print(a)

【讨论】:

你应该只发布完整的答案,而不是关于如何改进代码的 cmets。那些可以留在问题上的 cmets 或 pehaps na Answer... 所以,帮助我提高理解力。在 alexce 的原始问题的上下文中,我的答案如何或将成为“完整”答案? 见this help page;它与大多数论坛等有点不同,只提供诸如此类的有用提示就可以了。这样做的最大好处是,当您通过互联网搜索或其他方式进入这样的页面时,它大大减少了“噪音”的数量(在论坛上,您有时会有页面和垃圾页面需要挖掘).. . 感谢帮助页面链接。但是,我没有看到任何提到“完整”答案的内容,我仍然对是什么让我的答案不完整感到困惑?特别是,考虑到我使用了该人的原始问题并补充了我的解决方案。【参考方案3】:

这意味着商店返回的数据由于某种原因不包含您寻找的元素。

在代码中添加一些适当的错误处理,以捕获异常并在中断时转储输入。这样,您可以查看下载的内容并改进代码。

第一步是:

try:
    a = soup.find(text=('Socket')).find_next('dd').string

    print(a)
except:
    print(plain_text)
    raise

如果文本很多,则将其写入文件。

将这么多操作串在一行中也很危险。如果出现问题,那么您将不知道是什么。将其拆分为几行,以便您快速查看是否可以找到Socketdd 元素等。

【讨论】:

“你应该改进你的错误处理”似乎更适合评论而不是回答我......

以上是关于BeautifulSoup 有时会出现异常的主要内容,如果未能解决你的问题,请参考以下文章

ajax异步提交 有时会出现无bug的数据处理异常-----debug没有问题,正常运行却数据处理不正确,极少机会会出现正常的处理结果

有时发生错误的奇怪组

使用动态滚动解析网页的所有链接

为啥 BeautifulSoup 与“从未检索到任务异常”相关?

异常处理升级版

当客户端甚至无法连接到 WCF 服务器时,为啥会出现“服务器堆栈跟踪”异常?