【问题标题】:How to find elements by class如何按类查找元素
【发布时间】:2011-06-29 18:52:29
【问题描述】:

我在使用 Beautifulsoup 解析具有“class”属性的 HTML 元素时遇到问题。代码是这样的

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'

如何摆脱这个错误?

【问题讨论】:

    标签: python html web-scraping beautifulsoup


    【解决方案1】:

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

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

    【讨论】:

    • @Klaus- 如果我想使用 findAll 怎么办?
    • 这仅适用于完全匹配。 <.. class="stylelistrow"> 匹配但不匹配 <.. class="stylelistrow button">。
    • @pyCthon 查看@jmunsch 的答案,BS 现在支持class_,它可以正常工作。
    • _class 如果您有多个类,则只会匹配确切的类字符串。在这种情况下,您可以使用:soup.select("p.stylelistrow.another"),例如匹配 <p class="stylelistrow another yetAnother">
    • @Wernight 目前使用 BS4 (4.7.1) 和 soup.find_all("div", {"class": "stylelistrow"}) 可用于精确的 <.. class="stylelistrow"> 并包含 <.. class="stylelistrow button"> 匹配项。
    【解决方案2】:

    来自文档:

    As of Beautiful Soup 4.1.2, you can search by CSS class using the keyword argumentclass_:

    soup.find_all("a", class_="sister")
    

    在这种情况下是:

    soup.find_all("div", class_="stylelistrow")
    

    它也适用于:

    soup.find_all("div", class_="stylelistrowone stylelistrowtwo")
    

    【讨论】:

    • 你也可以使用列表:soup.find_all("a", ["stylelistrowone", "stylelistrow"]) 如果你的课程不多会更安全。
    • 这应该是公认的答案,它比其他选择更正确、更简洁。
    • 补充@NunoAndré 对 BeautifulSoup 3 的回答:soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']})。
    • @Timo 我猜你可以在搜索类以外的属性时使用 dict 方式,所以可能类似于{'data-item': ['1']} ex。 <a data-item="1" />
    • 需要注意的一点是,当你给class_="class_1 class2" 时,它匹配“精确字符串”,所以即使"class_2 class_1" 也不会匹配。要搜索多个类(全部必需),您应该使用选择器 soup.select('div.class_1.class_2') 这匹配 "class_1 class_2" 和 "class_2 class_1"。
    【解决方案3】:

    更新:2016 在最新版本的 beautifulsoup 中,方法 'findAll' 已重命名为 '找到所有'。 Link to official documentation

    因此答案将是

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

    【讨论】:

      【解决方案4】:

      CSS 选择器

      单类第一场比赛

      soup.select_one('.stylelistrow')
      

      匹配列表

      soup.select('.stylelistrow')
      

      复合类(即 AND 另一个类)

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

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

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

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

      bs4 4.7.1 +

      innerText 包含字符串的特定类

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

      注意

      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)')
      

      【讨论】:

      • 这很适合我只通过类而不是元素类型来查找的地方。
      【解决方案5】:

      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) ?
      • 因为 stylelistrow2 会匹配。更好的评论是“为什么不使用 string.find() 而不是 re?”
      • lambda x: 'stylelistrow' in x.split()简洁美观
      • 我讨厌正则表达式。谢谢! (更新答案)|保留“x 和”以测试无
      【解决方案6】:

      直截了当的方法是:

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

      确保你拿走了findAll的外壳,不是findall

      【讨论】:

      • 这仅适用于完全匹配。 &lt;.. class="stylelistrow"&gt; 匹配但不匹配 &lt;.. class="stylelistrow button"&gt;。
      【解决方案7】:

      如何按类查找元素

      我在使用 Beautifulsoup 解析具有“class”属性的 html 元素时遇到问题。

      你可以很容易地找到一个类,但如果你想通过两个类的交集找到,那就有点困难了,

      来自documentation(已添加重点):

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

      css_soup.select("p.strikeout.body")
      # [<p class="body strikeout"></p>]
      

      为了清楚起见,这只会选择同时是三振和正文类的 p 标签。

      要在一组类中查找 any 的交集(不是交集,而是联合),您可以为 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 已从 camelCase 重命名为更 Pythonic 的 find_all。

      【讨论】:

        【解决方案8】:

        从 BeautifulSoup 4+ 开始,

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

        mydivs = soup.find_all('div', 'class_name')
        

        或者,如果您有多个类名,只需将类名列表作为参数传递,例如:

        mydivs = soup.find_all('div', ['class1', 'class2'])
        

        【讨论】:

          【解决方案9】:

          使用class_=如果你想找到元素不声明HTML标签。

          对于单个元素:

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

          对于多个元素:

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

          【讨论】:

            【解决方案10】:

            以下内容对我有用

            a_tag = soup.find_all("div",class_='full tabpublist')
            

            【讨论】:

              【解决方案11】:

              先尝试检查div是否有class属性,像这样:

              soup = BeautifulSoup(sdata)
              mydivs = soup.findAll('div')
              for div in mydivs:
                  if "class" in div:
                      if (div["class"]=="stylelistrow"):
                          print div
              

              【讨论】:

              • 那行不通。我猜你的方法是对的,但第 4 行没有按预期工作。
              • 啊,我以为 div 像字典一样工作,我对 Beautiful Soup 不是很熟悉,所以只是猜测。
              【解决方案12】:

              这对我来说可以访问 class 属性(在 beautifulsoup 4 上,与文档所说的相反)。 KeyError 是返回一个列表而不是字典。

              for hit in soup.findAll(name='span'):
                  print hit.contents[1]['class']
              

              【讨论】:

                【解决方案13】:

                我们也可以使用 lxml,它支持 xpath 并且速度非常快!

                from lxml import html, etree 
                
                attr = html.fromstring(html_text)#passing the raw html
                handles = attr.xpath('//div[@class="stylelistrow"]')#xpath exresssion to find that specific class
                
                for each in handles:
                    print(etree.tostring(each))#printing the html as string
                

                【讨论】:

                  【解决方案14】:

                  其他答案对我不起作用。

                  在其他答案中,findAll 正在用于汤对象本身,但我需要一种方法来通过类名查找从我在执行 findAll 后获得的对象中提取的特定元素内的对象。

                  如果您尝试在嵌套的 HTML 元素中进行搜索以按类名获取对象,请尝试以下操作 -

                  # parse html
                  page_soup = soup(web_page.read(), "html.parser")
                  
                  # filter out items matching class name
                  all_songs = page_soup.findAll("li", "song_item")
                  
                  # traverse through all_songs
                  for song in all_songs:
                  
                      # get text out of span element matching class 'song_name'
                      # doing a 'find' by class name within a specific song element taken out of 'all_songs' collection
                      song.find("span", "song_name").text
                  

                  注意事项:

                  1. 我没有明确将搜索定义为“类”属性findAll("li", {"class": "song_item"}),因为它是我要搜索的唯一属性,如果您不专门搜索,它将默认搜索类属性告诉您要查找哪个属性。

                  2. 当您执行findAll 或find 时,生成的对象属于bs4.element.ResultSet 类,它是list 的子类。您可以使用ResultSet 的所有方法,在任意数量的嵌套元素中(只要它们是ResultSet 类型)进行查找或全部查找。

                  3. 我的 BS4 版本 - 4.9.1,Python 版本 - 3.8.1

                  【讨论】:

                    【解决方案15】:

                    关于@Wernight 对top answer 部分匹配的评论...

                    你可以部分匹配:

                    • &lt;div class="stylelistrow"&gt; 和
                    • &lt;div class="stylelistrow button"&gt;

                    gazpacho:

                    from gazpacho import Soup
                    
                    my_divs = soup.find("div", {"class": "stylelistrow"}, partial=True)
                    

                    两者都将被捕获并作为Soup 对象列表返回。

                    【讨论】:

                      【解决方案16】:

                      单身

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

                      多个

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

                      【讨论】:

                        【解决方案17】:

                        这对我有用:

                        for div in mydivs:
                            try:
                                clazz = div["class"]
                            except KeyError:
                                clazz = ""
                            if (clazz == "stylelistrow"):
                                print div
                        

                        【讨论】:

                          【解决方案18】:

                          这应该可行:

                          soup = BeautifulSoup(sdata)
                          mydivs = soup.findAll('div')
                          for div in mydivs: 
                              if (div.find(class_ == "stylelistrow"):
                                  print div
                          

                          【讨论】:

                            【解决方案19】:

                            以下应该可以工作

                            soup.find('span', attrs={'class':'totalcount'})
                            

                            将“totalcount”替换为您的班级名称,将“span”替换为您要查找的标签。此外,如果您的类包含多个带空格的名称,只需选择一个并使用。

                            附:这将找到具有给定条件的第一个元素。如果要查找所有元素,请将 'find' 替换为 'find_all'。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2014-02-15
                              • 2021-03-05
                              • 2023-01-03
                              • 1970-01-01
                              相关资源
                              最近更新 更多