如何按类名查找元素

655

我在使用BeautifulSoup解析HTML元素中的"class"属性时遇到了问题。 代码如下:

soup = BeautifulSoup(sdata)
mydivs = soup.findAll('div')
for div in mydivs: 
    if (div["class"] == "stylelistrow"):
        print div
我在脚本完成后的同一行收到了一个错误提示。
File "./beautifulcoding.py", line 130, in getlanguage
  if (div["class"] == "stylelistrow"):
File "/usr/local/lib/python2.6/dist-packages/BeautifulSoup.py", line 599, in __getitem__
   return self._getAttrMap()[key]
KeyError: 'class'

如何消除这个错误?

19个回答

1043

使用BS3,您可以细化搜索以仅查找具有给定类的那些div:

mydivs = soup.find_all("div", {"class": "stylelistrow"})

70
这仅适用于完全匹配。<.. class="stylelistrow">是匹配的,但<.. class="stylelistrow button">不匹配。 - Wernight
@Wernight,你找到解决方案了吗? - pyCthon
7
@pyCthon请看@jmunsch的答案,现在BS已经支持了class_,可以正常工作。 - Wernight
4
如果一个标签有多个类,想要匹配特定的类名,需要使用soup.select("p.stylelistrow.another")语法。这样可以精确匹配到类名为"stylelistrow"和"another"的标签,例如<p class="stylelistrow another yetAnother"> - smoothware
2
@Wernight 目前使用 BS4(4.7.1),soup.find_all("div", {"class": "stylelistrow"}) 可以匹配精确的 <.. class="stylelistrow"> 和包含的 <.. class="stylelistrow button"> - Girrafish
显示剩余3条评论

436

13
你也可以使用列表: soup.find_all("a", ["stylelistrowone", "stylelistrow"]) 如果你没有很多类,这样做更安全。 - Nuno André
7
这个答案应该被采纳,因为它比其它的选项更正确且更简明扼要。 - loopbackbee
3
@NunoAndré回答BeautifulSoup 3的补充:soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']}) - Bowen Xu
1
@Timo 我猜你可以在搜索除了 class 以外的属性时使用字典方式,所以可能是这样的 {'data-item': ['1']},例如 <a data-item="1" /> - jmunsch
2
需要注意的一点是,当你使用 class_="class_1 class2" 时,它会匹配“完全字符串”,因此即使是 "class_2 class_1" 也不会匹配。如果要搜索具有多个类(所有必需的),则应使用选择器 soup.select('div.class_1.class_2'),这将匹配 "class_1 class_2""class_2 class_1" - Hrishikesh
显示剩余3条评论

81

更新:2016年,在最新版本的beautifulsoup中,方法“findAll”已更名为“find_all”。官方文档链接

更改的方法名称列表

因此答案将是

soup.find_all("html_element", class_="your_class_name")

55

CSS选择器

单个类名首次匹配

soup.select_one('.stylelistrow')

比赛列表

soup.select('.stylelistrow')

复合类(即与另一个类别同时存在)

soup.select_one('.stylelistrow.otherclassname')
soup.select('.stylelistrow.otherclassname')

复合类名中的空格,例如class = stylelistrow otherclassname,将被替换为“.”。您可以继续添加类。

类列表(或 - 匹配任何一个)

soup.select_one('.stylelistrow, .otherclassname')
soup.select('.stylelistrow, .otherclassname')

包含字符串(例如“stylelistrow”)的类属性:

以“style”开头:

[class^=style]

以 "row" 结尾

[class$=row]

包含“list”:

[class*=list]

^、$ 和 * 都是运算符。在此阅读更多: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors

例如以锚点标签为例,如果你想要排除这个类,选择没有这个类的锚点标签:

a:not(.stylelistrow)

您可以在:not()伪类中传递简单、复合和复杂的CSS选择器列表。请参见https://facelessuser.github.io/soupsieve/selectors/pseudo-classes/#:not


bs4 4.7.1以上版本

包含特定字符串的innerText类

soup.select_one('.stylelistrow:contains("some string")')
soup.select('.stylelistrow:contains("some string")')

N.B.

soupsieve 2.1.0 + Dec'2020 onwards

新增:为避免与未来的CSS规范发生冲突,非标准伪类现在将以“:-soup-”前缀开头。 因此,:contains() 现在将被称为 :-soup-contains(),但是在一段时间内,仍将允许使用已弃用的 :contains() 形式,并警告用户迁移到 :-soup-contains()

新增:添加了一个新的非标准伪类 :-soup-contains-own(),其操作方式类似于 :-soup-contains(),但它只查看与当前作用域元素直接关联的文本节点,而不是其后代。

具有特定子元素(如a标记)的特定类

soup.select_one('.stylelistrow:has(a)')
soup.select('.stylelistrow:has(a)')

1
这对我来说很有效,因为我只想按类而不是元素类型查找。 - Brian C.

24

针对BeautifulSoup 3:

soup.findAll('div',
             {'class': lambda x: x 
                       and 'stylelistrow' in x.split()
             }
            )

将找到所有这些:

<div class="stylelistrow">
<div class="stylelistrow button">
<div class="button stylelistrow">

为什么不使用re.search('.stylelistrow.', x)呢? - rjurney
因此,stylelistrow2将匹配。更好的注释是“为什么不使用string.find()而不是re?” - FlipMcF
4
lambda x: 'stylelistrow' in x.split()是简洁而优美的。 - fferri
1
我讨厌正则表达式。谢谢!(更新答案)| 保留“x和”以测试是否为None。 - FlipMcF
保留 'x and' 以测试 None - lam vu Nguyen

19

一种直接的方法是:

soup = BeautifulSoup(sdata)
for each_div in soup.findAll('div',{'class':'stylelist'}):
    print each_div

请确保正确拼写 findAll,不是 findall


6
仅对完全匹配有效。 <.. class="stylelistrow"> 可以匹配,但 <.. class="stylelistrow button"> 不能。 - Wernight

17

如果您想查找没有指定HTML标签的元素,请使用class_=

对于单个元素:

soup.find(class_='my-class-name')

对于多个元素:

soup.find_all(class_='my-class-name')

15

如何按类查找元素

我在使用Beautifulsoup解析具有"class"属性的HTML元素时遇到了问题。

你可以很容易地按一个类查找,但如果想按两个类的交集查找,就有些困难了。

文档(强调部分为原文)中得知:

如果你想搜索匹配两个或多个 CSS 类的标签,应该使用 CSS 选择器:

css_soup.select("p.strikeout.body")
# [<p class="body strikeout"></p>]
要明确的是,这只选定了同时具有删除线和body类的p标签。
要查找一组类的任何交集(不是交集,而是并集),您可以将列表提供给class_关键字参数(从4.1.2开始):
soup = BeautifulSoup(sdata)
class_list = ["stylelistrow"] # can add any other classes to this list.
# will find any divs with any names in class_list:
mydivs = soup.find_all('div', class_=class_list) 

还要注意,findAll已经从驼峰式命名更改为更符合Python风格的find_all


11

从BeautifulSoup 4+开始,

如果你只有一个类名,可以直接将类名作为参数传递,例如:

mydivs = soup.find_all('div', 'class_name')
如果您有多个类名,只需将类名列表作为参数传递,如下所示:
mydivs = soup.find_all('div', ['class1', 'class2'])

4

单个

soup.find("form",{"class":"c-login__form"})

多个

res=soup.find_all("input")
for each in res:
    print(each)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接