【问题标题】:Python issue: TypeError: unhashable type: 'slice' during web scrapingPython 问题:TypeError: unhashable type: 'slice' during web scraping
【发布时间】:2018-05-03 05:00:10
【问题描述】:

我正在尝试从网站上抓取一些信息。我能够成功地抓取我正在寻找的文本,但是当我尝试创建一个将文本附加在一起的函数时,我得到了一个不可散列类型的 TypeError。

你知道这里会发生什么吗?有谁知道如何解决这个问题?

这里是有问题的代码:

records = []
for result in results:
    name = result.contents[0][0:-1]

这里是完整的代码,用于复制目的:

import requests
from bs4 import BeautifulSoup

r = requests.get('https://skinsalvationsf.com/2012/08/updated-comedogenic-ingredients-list/')
soup = BeautifulSoup(r.text, 'html.parser')
results = soup.find_all('td', attrs={'valign':'top'})

records = []
for result in results:
    name = result.contents[0][0:-1]

results 项目的样本:

<td valign="top" width="33%">Acetylated Lanolin <sup>5</sup></td>,
<td valign="top" width="33%">Coconut Butter<sup> 8</sup></td>,
...
<td valign="top" width="33%"><sup> </sup></td>

提前致谢!!

【问题讨论】:

  • 该错误消息几乎总是意味着您认为您有一个列表(或其他序列),但实际上您有一个 dict(或其他映射)。错误消息可能会更好一些,但重点是:从 dict 中切出一个范围没有任何意义。
  • 至于如何修复它……嗯,这取决于contents[0] 中的内容、您认为其中的内容以及您希望[0:-1] 选择的内容。
  • &gt;&gt;&gt; first_result = results[0] Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; NameError: name 'results' is not defined 这就是我得到的:|
  • 当我运行这个时,我从网络服务器收到一个 403 错误,这当然意味着汤最终是空的,结果是空的,并且您的错误无法重现。同样,如果你去掉 requestsbs4 的东西,只给我们一个 results 的示例字符串来证明问题,那会好得多。如果不清楚如何缩小问题范围,请阅读minimal reproducible example;真的很有帮助。
  • results= &lt;td valign="top" width="33%"&gt;Acetylated Lanolin &lt;sup&gt;5&lt;/sup&gt;&lt;/td&gt; 甚至不是有效代码。

标签: python function loops beautifulsoup scraper


【解决方案1】:

在您收集的某些结果中,contents 不包含文本,而仅包含 Tag 对象,因此当您尝试从 Tag 的属性字典中选择一个切片时,您会得到一个 TypeError

您可以使用 try-except 块捕获此类错误,

for result in results:
    try:
        name = result.contents[0][0:-1]
    except TypeError:
        continue

或者您可以使用.strings 仅选择NavigableString 内容,

for result in results:
    name = list(result.strings)[0][0:-1]

但它似乎只是最后一个没有文本内容的项目,所以你可以忽略它。

results = soup.find_all('td', attrs={'valign':'top'})[:-1]

for result in results:
    name = result.contents[0][:-1]

【讨论】:

  • .strings 的第二种方法有效!非常感谢!
【解决方案2】:

要了解您收到TypeError: unhashable type: 'slice' 的原因,请阅读t.m.adam's answer。简而言之,在最后一次迭代中,result 变量指向 bs4.element.Tag 对象,而不是 bs4.element.NavigableString

下面是使用 try-except 块的工作解决方案,因为列表中的最后 2 个 &lt;td&gt; 元素不包含“stripped_strings”,并且会产生 ValueError: not enough values to unpack (expected 2, got 0)

代码:(Python 3.6+,如果你想使用f-strings

from bs4 import BeautifulSoup
import requests

url = 'https://skinsalvationsf.com/2012/08/updated-comedogenic-ingredients-list/'
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'}
html = requests.get(url, headers=headers).text
soup = BeautifulSoup(r.text, 'html.parser')

tds = soup.find_all('td')
for td in tds:
    try:
        ingredient, rating = td.stripped_strings
    except ValueError:
        pass
    else:
        print(f'{ingredient} -> {rating}')

输出:

Acetylated Lanolin -> 5
Coconut Butter -> 8
...
Xylene -> 7
Octyl Palmitate -> 7

您也可以去掉整个 try-except-else 并省略最后两个 &lt;td&gt;

tds = soup.find_all('td')[:-2]
for td in tds:
    ingredient, rating = td.stripped_strings
    ...

但是,网站的维护者可能会决定添加或删除某些成分,从而导致代码遗漏某些成分。

【讨论】:

  • 这个方法也有效!谢谢你的解释!
猜你喜欢
  • 2018-08-12
  • 2019-04-17
  • 1970-01-01
  • 1970-01-01
  • 2017-09-03
  • 2015-02-11
  • 2020-12-10
  • 2020-05-11
  • 2022-08-11
相关资源
最近更新 更多