Como encontrar elementos por classe


386

Estou tendo problemas para analisar elementos HTML com o atributo "class" usando Beautifulsoup. O código fica assim

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

Eu recebo um erro na mesma linha "depois" do script terminar.

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'

Como faço para me livrar desse erro?

Respostas:


646

Você pode refinar sua pesquisa para encontrar apenas os divs com uma determinada classe usando o BS3:

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

@ Klaus- e se eu quiser usar o findAll?

11
Obrigado por isso. Não é apenas para @class, mas para qualquer coisa.
prageeth

41
Isso funciona apenas para correspondências exatas. <.. class="stylelistrow">corresponde, mas não <.. class="stylelistrow button">.
Wernight

4
@pyCthon Veja a resposta para @jmunsch, o BS agora suporta o class_que funciona corretamente.
Wernight

25
A partir de beautifulsoup4, o findAll é agora find_all
Neoecos

273

A partir da documentação:

No Beautiful Soup 4.1.2, você pode pesquisar por classe CSS usando o argumento de palavra-chave class_ :

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

Qual nesse caso seria:

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

Também funcionaria para:

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

5
Você também pode usar listas: soup.find_all("a", ["stylelistrowone", "stylelistrow"])é mais seguro se você não tiver muitas classes.
Nuno André

4
Essa deve ser a resposta aceita, é mais correta e concisa do que as alternativas.
21416 Gncalopp

11
Suplemento @ resposta de NunoAndré para BeautifulSoup 3: soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']}).
21718 Brad

55

Atualização: 2016 Na versão mais recente do beautifulsoup, o método 'findAll' foi renomeado para 'find_all'. Link para documentação oficial

Lista de nomes de métodos alterados

Portanto, a resposta será

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

18

Específico para BeautifulSoup 3:

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

Encontrará todos estes:

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

Por que não pesquisar novamente ('. * Stylelistrow. *', X)?
rjurney

porque stylelistrow2 corresponderá. Melhor comentário é "por que não usar string.find () em vez de re?"
FlipMcF

2
lambda x: 'stylelistrow' in x.split()é simples e bonito
fferri

E eu odeio regexes. Obrigado! (atualizando resposta) | mantendo o 'x e' para testar o None
FlipMcF 17/07/2015

16

Uma maneira direta seria:

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

Certifique-se de pegar a caixa de findAll , não é tudo


4
Isso funciona apenas para correspondências exatas. <.. class="stylelistrow">corresponde, mas não <.. class="stylelistrow button">.
Wernight

11

Como encontrar elementos por classe

Estou tendo problemas para analisar elementos html com o atributo "class" usando Beautifulsoup.

Você pode encontrar facilmente por uma classe, mas se quiser encontrar pela interseção de duas classes, é um pouco mais difícil,

A partir da documentação (ênfase adicionada):

Se você deseja procurar por tags que correspondam a duas ou mais classes CSS, use um seletor de CSS:

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

Para ficar claro, isso seleciona apenas as tags p que são de strikeout e de classe corporal.

Para encontrar a interseção de qualquer um em um conjunto de classes (não a interseção, mas a união), você pode dar uma lista ao class_argumento da palavra - chave (a partir de 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) 

Observe também que findAll foi renomeado do camelCase para o mais Pythonic find_all.


11

Seletores CSS

primeira partida de classe única

soup.select_one('.stylelistrow')

lista de correspondências

soup.select('.stylelistrow')

classe composta (ou seja, E outra classe)

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

Os espaços nos nomes das classes compostas, por exemplo, class = stylelistrow otherclassnamesão substituídos por ".". Você pode continuar adicionando classes.

lista de classes (OU - corresponde à que estiver presente

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

bs4 4.7.1 +

Classe específica que innerTextcontém uma sequência

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

Classe específica que possui um determinado elemento filho, por exemplo, atag

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

5

A partir do BeautifulSoup 4+,

Se você tiver um único nome de classe, basta passar o nome da classe como parâmetro como:

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

Ou, se você tiver mais de um nome de classe, basta passar a lista de nomes de classe como parâmetro como:

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

3

Tente verificar se a div tem um atributo de classe primeiro, assim:

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

11
Isso não funciona. Eu acho que sua abordagem estava certa, mas a quarta linha não funciona conforme o esperado.
Neo

11
Ah, eu pensei que div funcionava como um dicionário, não estou realmente familiarizado com a Beautiful Soup, então foi apenas um palpite.
Mew

3

Isso funciona para eu acessar o atributo de classe (no beautifulsoup 4, ao contrário do que diz a documentação). O KeyError vem uma lista retornada, não um dicionário.

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

3

o seguinte funcionou para mim

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

1

Isso funcionou para mim:

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

1

Como alternativa, podemos usar o lxml, ele suporta xpath e muito rápido!

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

0

Isso deve funcionar:

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

0

Outras respostas não funcionaram para mim.

Em outras respostas, ele findAllestá sendo usado no próprio objeto de sopa, mas eu precisava de uma maneira de encontrar uma busca pelo nome da classe em objetos dentro de um elemento específico extraído do objeto que obtive depois de fazer findAll.

Se você estiver tentando fazer uma pesquisa dentro de elementos HTML aninhados para obter objetos pelo nome da classe, tente abaixo -

# 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

Pontos a serem observados:

  1. Não estou definindo explicitamente a pesquisa para estar no atributo 'class' findAll("li", {"class": "song_item"}), pois é o único atributo que estou pesquisando e, por padrão, procurará o atributo class se você não informar exclusivamente em qual atributo deseja encontrar.

  2. Quando você faz um findAllou find, o objeto resultante é da classe bs4.element.ResultSetque é uma subclasse de list. Você pode utilizar todos os métodos de ResultSet, dentro de qualquer número de elementos aninhados (desde que sejam do tipo ResultSet) para localizar ou encontrar todos.

  3. Minha versão BS4 - 4.9.1, versão Python - 3.8.1


0

O seguinte deve funcionar

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

substitua 'totalcount' pelo nome da sua classe e 'span' pela tag que você está procurando. Além disso, se sua classe contiver vários nomes com espaço, basta escolher um e usar.

PS Este encontra o primeiro elemento com determinados critérios. Se você deseja encontrar todos os elementos, substitua 'find' por 'find_all'.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.