【问题标题】:BeautifulSoup findAll() given multiple classes?BeautifulSoup findAll() 给定了多个类?
【发布时间】:2013-09-14 13:36:24
【问题描述】:

我想从网站上抓取项目列表,并保留它们的显示顺序。这些项目被组织在一个表格中,但它们可以是两个不同类别之一(以随机顺序)。

有没有办法提供多个类并让 BeautifulSoup4 找到任何给定类中的所有项目?

我需要实现这段代码的功能,除了保留源代码中的项目顺序:

items = soup.findAll(True,{'class':'class1'})
items += soup.findAll(True,{'class':'class2'})

【问题讨论】:

  • 感谢 alecxe 和 Roman Pekar 帮助我解决了这个问题。我能够使用部分类名和alecxe更新答案中建议的额外检查来实现我想要的。

标签: python html beautifulsoup html-parsing


【解决方案1】:

你可以这样做

soup.findAll(True, {'class':['class1', 'class2']})

示例:

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup('<html><body><div class="class1"></div><div class="class2"></div><div class="class3"></div></body></html>')
>>> soup.findAll(True, {"class":["class1", "class2"]})
[<div class="class1"></div>, <div class="class2"></div>]

【讨论】:

  • 在我的代码中,这将返回一个空列表,与 alecxe 的解决方案相同。请参阅他对我的代码的回复下方的评论。
  • @sebo 试试这个:soup.findAll(True, {"class":["equal", "up"]}).
  • @alecxe 这行得通,为您 +1,但仍在尝试找到如何使用完整的类名来使其工作
  • @RomanPekar 谢谢。我认为bs4 不会将class 过滤器应用于整个class 属性值,它会按空间拆分类。见*.com/questions/1242755/…
  • @RomanPekar 我认为有一种解决方法 - 在循环内添加额外的检查,请参阅我更新的答案。你怎么看?
【解决方案2】:

我是 Python 新手,使用 BeautifulSoup,但我的回答可能对您有所帮助。我遇到了同样的情况,我必须找到一个标签的多个类,所以我只需将这些类传递到一个数组中,它就对我有用。 这是代码sn-p

# Search with single Class
    find_all("tr",  {"class":"abc"})
# Search with multiple classes
    find_all("tr",  {"class": ["abc", "xyz"]})

【讨论】:

  • {"class": ["abc", "xyz"]} 对应于or 选择器还是and 选择器?
  • 对应or
  • 我如何做到and
  • 您可以使用select 代替find_all。 @SundeepPidugu select('div.abc.xyz')
【解决方案3】:

一种方法是使用正则表达式而不是类名:

import re
import requests
from bs4 import BeautifulSoup


s = requests.Session()
link = 'https://leaderboards.guildwars2.com/en/na/achievements'
r = s.get(link)


soup = BeautifulSoup(r.text)
for item in soup.findAll(True, {"class": re.compile("^(equal|up)$")}):
    if 'achievements' in item.attrs['class'] and 'number' in item.attrs['class']:
        print item

【讨论】:

  • 感谢您的快速回复。现在,这个调用并没有返回任何东西。这可能是由于类名中有空格引起的吗? (例如“class 1”)对不起,我对正则表达式一无所知。
  • @sebo 您能否展示您正在使用的代码,以便我重现并解决问题?
  • 剥离后,这是我正在查看的代码:import requests from bs4 import BeautifulSoup s = requests.Session() link = 'https://leaderboards.guildwars2.com/en/na/achievements' r = s.get(link) soup = BeautifulSoup(r.text) items = soup.findAll(True, {"class":["equal achievements number", "up achievements number"]}) 这是应用 Roman Pekar 的解决方案,但它返回一个空列表。使用正则表达式解决方案也会发生同样的事情。不过,一次检索任一类都可以。对不起,糟糕的格式。
  • @sebo 工作正常吗soup.findAll(True, {"class": ".*achievements number.*"})
  • 这也返回一个空列表。
【解决方案4】:

或者使用最新版本的 BeautifulSoup:

find_all('a', class_=['class1', 'class2'])

使用“class”会返回错误,因此他们使用“class_”代替。

【讨论】:

  • 这是or,对于and,请参阅其他答案的评论。
【解决方案5】:
    <html>
        <body>
            <div class="cls1">ok</div>
            <div class="cls2">hi</div>
            <div class="cls1 cls2">both</div>
        </body>
    </html>

假设 html 变量包含上面的 html 代码

    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html)
    divs = soup.find_all('div', class_=['cls1', 'cls2'])
    print(divs)

这将输出:

[<div class="cls1">ok</div>, <div class="cls2">hi</div>, <div class="cls1 cls2">both</div>]

它是“OR”运算符而不是“AND”,也就是说,元素不需要同时具有两个类。
要使用“AND”运算符,您可以使用select('div.cls1.cls2')

    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html)
    divs = soup.select('div.cls1.cls2')
    print(divs)

这将输出:

[<div class="cls1 cls2">both</div>]

【讨论】:

    【解决方案6】:

    如果您使用 Url 作为参数,请不要忘记传递标头。我为获得这些 div 元素和 2 个类而奋斗了大约一个小时,但它对 mi 不起作用,直到我注意到我忘记传递 this 标头。

    header = {
        "Accept-Language": "es-ES,es;q=0.9",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
    }
    url = 'something.com'
    response = requests.get(url=url,headers=header)
    response.raise_for_status()
    data = response.text
    
    soup = BeautifulSoup(data, 'html.parser')  
    
    elements = soup.select('div.fde444d7ef._c445487e2')
    

    【讨论】: