Come trovare elementi per classe


386

Sto riscontrando problemi nell'analizzare gli elementi HTML con l'attributo "class" usando Beautifulsoup. Il codice è simile al seguente

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

Viene visualizzato un errore sulla stessa riga "dopo" lo script termina.

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'

Come posso eliminare questo errore?

Risposte:


646

Puoi affinare la tua ricerca per trovare solo quei div con una data classe usando BS3:

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

@ Klaus- cosa succede se voglio usare findAll invece?

1
Grazie per questo. Non è solo per @class ma per qualsiasi cosa.
Prageeth l'

41
Funziona solo per corrispondenze esatte. <.. class="stylelistrow">partite ma non <.. class="stylelistrow button">.
Wernight,

4
@pyCthon Vedi la risposta per @jmunsch, BS ora supporta class_che funziona correttamente.
Wernight,

25
A partire da beautifulsoup4, findAll ora è find_all
Neoecos,

273

Dalla documentazione:

A partire da Beautiful Soup 4.1.2, puoi cercare per classe CSS usando l'argomento keyword class_ :

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

Che in questo caso sarebbe:

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

Funzionerebbe anche per:

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

5
Puoi anche usare le liste: soup.find_all("a", ["stylelistrowone", "stylelistrow"])è più sicuro se non hai molte classi.
Nuno André,

4
Questa dovrebbe essere la risposta accettata, è sia più corretta che concisa rispetto alle alternative.
goncalopp,

1
Supplemento a @ risposta di NunoAndré per BeautifulSoup 3: soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']}).
Brad


18

Specifico per BeautifulSoup 3:

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

Troverà tutti questi:

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

Perché non re.search ('. * Stylelistrow. *', X)?
rjurney,

perché allora stylelistrow2 corrisponderà. Il commento migliore è "perché non usare string.find () invece di re?"
FlipMcF

2
lambda x: 'stylelistrow' in x.split()è semplice e bello
fferri

E odio le regex. Grazie! (aggiornamento della risposta) | mantenendo la 'x e' per testare None
FlipMcF

16

Un modo semplice sarebbe:

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

Assicurati di prendere l'involucro di findAll , non è findall


4
Funziona solo per corrispondenze esatte. <.. class="stylelistrow">partite ma non <.. class="stylelistrow button">.
Wernight,

11

Come trovare elementi per classe

Sto riscontrando problemi nell'analizzare gli elementi html con l'attributo "class" usando Beautifulsoup.

Puoi trovarlo facilmente per una classe, ma se vuoi trovarlo per l'intersezione di due classi, è un po 'più difficile,

Dalla documentazione (enfasi aggiunta):

Se si desidera cercare tag che corrispondono a due o più classi CSS, è necessario utilizzare un selettore CSS:

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

Per essere chiari, questo seleziona solo i tag p che sono sia strikeout che body class.

Per trovare l'intersezione di qualsiasi in un insieme di classi (non l'intersezione, ma l'unione), è possibile fornire un elenco class_all'argomento della parola chiave (a partire dalla 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) 

Si noti inoltre che findAll è stato rinominato da camelCase a Pythonic find_all.


11

Selettori CSS

prima partita di classe singola

soup.select_one('.stylelistrow')

elenco di partite

soup.select('.stylelistrow')

classe composta (ovvero AND un'altra classe)

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

Gli spazi nei nomi delle classi composte, ad esempio, class = stylelistrow otherclassnamesono sostituiti da ".". Puoi continuare ad aggiungere classi.

elenco di classi (OPPURE - corrisponde a qualsiasi presente

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

bs4 4.7.1 +

Classe specifica che innerTextcontiene una stringa

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

Classe specifica che ha un determinato elemento figlio, ad esempio atag

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

5

A partire da BeautifulSoup 4+,

Se hai un solo nome di classe, puoi semplicemente passare il nome della classe come parametro come:

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

Oppure, se hai più di un nome di classe, passa l'elenco dei nomi di classe come parametro come:

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

3

Prova a verificare se il div ha prima un attributo di classe, in questo modo:

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

1
Non funziona Immagino che il tuo approccio fosse corretto, ma la quarta riga non funziona come previsto.
Neo,

1
Ah, pensavo che il div funzionasse come un dizionario, non ho molta familiarità con Beautiful Soup, quindi era solo una supposizione.
Mew,

3

Questo funziona per me per accedere all'attributo class (su beautifulsoup 4, contrariamente a quanto dice la documentazione). KeyError arriva un elenco restituito non un dizionario.

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

3

quanto segue ha funzionato per me

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

1

Questo ha funzionato per me:

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

1

In alternativa possiamo usare lxml, supporta xpath e molto velocemente!

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

Questo dovrebbe funzionare:

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

0

Altre risposte non hanno funzionato per me.

In altre risposte findAllviene utilizzato l'oggetto zuppa stesso, ma avevo bisogno di un modo per trovare un nome di classe sugli oggetti all'interno di un elemento specifico estratto dall'oggetto che ho ottenuto dopo averlo fatto findAll.

Se stai cercando di eseguire una ricerca all'interno di elementi HTML nidificati per ottenere oggetti in base al nome della classe, prova di seguito:

# 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

Punti da notare:

  1. Non sto definendo esplicitamente che la ricerca deve essere sull'attributo 'class' findAll("li", {"class": "song_item"}), poiché è l'unico attributo che sto cercando e cercherà di default l'attributo class se non dici esclusivamente su quale attributo vuoi trovare.

  2. Quando si esegue un findAllo find, l'oggetto risultante è di classe bs4.element.ResultSetche è una sottoclasse di list. È possibile utilizzare tutti i metodi di ResultSet, all'interno di qualsiasi numero di elementi nidificati (purché siano di tipo ResultSet) per fare una ricerca o trovare tutto.

  3. La mia versione BS4 - 4.9.1, versione Python - 3.8.1


0

Quanto segue dovrebbe funzionare

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

sostituisci "totalcount" con il nome della tua classe e "span" con il tag che stai cercando. Inoltre, se la tua classe contiene più nomi con spazio, basta sceglierne uno e usarlo.

PS Questo trova il primo elemento con determinati criteri. Se vuoi trovare tutti gli elementi, sostituisci "trova" con "trova".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.