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?

Neo
fonte

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 Byskov Pedersen
fonte
@ 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")
jmunsch
fonte
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")
soberano
fonte
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">
FlipMcF
fonte
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

Konark Modi
fonte
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.

Aaron Hall
fonte
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)')
QHarr
fonte
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'])
Shivam Shah
fonte
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
Mew
fonte
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']
Stgltz
fonte
3

o seguinte funcionou para mim

a_tag = soup.find_all("div",class_='full tabpublist')
Preetham DP
fonte
1

Isso funcionou para mim:

for div in mydivs:
    try:
        clazz = div["class"]
    except KeyError:
        clazz = ""
    if (clazz == "stylelistrow"):
        print div
Larry Symms
fonte
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
Sohan Das
fonte
0

Isso deve funcionar:

soup = BeautifulSoup(sdata)
mydivs = soup.findAll('div')
for div in mydivs: 
    if (div.find(class_ == "stylelistrow"):
        print div
Céu azul
fonte
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

ZeroFlex
fonte
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'.

hari sudhan
fonte