So finden Sie Elemente nach Klasse

386

Ich habe Probleme beim Analysieren von HTML-Elementen mit dem Attribut "class" mithilfe von Beautifulsoup. Der Code sieht so aus

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

Ich erhalte eine Fehlermeldung in derselben Zeile "nachdem" das Skript beendet wurde.

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'

Wie werde ich diesen Fehler beseitigen?

Neo
quelle

Antworten:

646

Sie können Ihre Suche verfeinern, um nur die Divs mit einer bestimmten Klasse mit BS3 zu finden:

mydivs = soup.findAll("div", {"class": "stylelistrow"})
Klaus Byskov Pedersen
quelle
@ Klaus- was ist, wenn ich stattdessen findAll verwenden möchte?
1
Danke dafür. Es ist nicht nur für @class, sondern für alles.
Prageeth
41
Dies funktioniert nur für genaue Übereinstimmungen. <.. class="stylelistrow">passt aber nicht <.. class="stylelistrow button">.
Wernight
4
@pyCthon Siehe Antwort für @jmunsch, BS unterstützt jetzt, class_was richtig funktioniert.
Wernight
25
Ab beautifulsoup4 ist das findAll jetzt find_all
Neoecos
273

Aus der Dokumentation:

Ab Beautiful Soup 4.1.2 können Sie mit dem Schlüsselwortargument nach CSS-Klasse suchen class_ :

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

Was in diesem Fall wäre:

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

Es würde auch funktionieren für:

soup.find_all("div", class_="stylelistrowone stylelistrowtwo")
jmunsch
quelle
5
Sie können auch Listen verwenden: soup.find_all("a", ["stylelistrowone", "stylelistrow"])Es ist sicherer, wenn Sie nicht viele Klassen haben.
Nuno André
4
Dies sollte die akzeptierte Antwort sein, sie ist sowohl korrekter als auch prägnanter als die Alternativen.
Goncalopp
1
Ergänzung zu @ NunoAndrés Antwort für BeautifulSoup 3 : soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']}).
Brad
55

Update: 2016 In der neuesten Version von beautifulsoup wurde die Methode 'findAll' in 'find_all' umbenannt. Link zur offiziellen Dokumentation

Liste der Methodennamen geändert

Daher wird die Antwort sein

soup.find_all("html_element", class_="your_class_name")
Oberherr
quelle
18

Speziell für BeautifulSoup 3:

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

Finden Sie alle diese:

<div class="stylelistrow">
<div class="stylelistrow button">
<div class="button stylelistrow">
FlipMcF
quelle
Warum nicht re.search ('. * Stylelistrow. *', X)?
rjurney
denn dann wird stylelistrow2 übereinstimmen. Besserer Kommentar ist "Warum nicht string.find () anstelle von re verwenden?"
FlipMcF
2
lambda x: 'stylelistrow' in x.split()ist einfach und schön
fferri
Und ich hasse Regexes. Vielen Dank! (Antwort aktualisieren) | Halten Sie das 'x und', um auf Keine zu testen
FlipMcF
16

Ein direkter Weg wäre:

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

Stellen Sie sicher, dass Sie das Gehäuse von findAll abnehmen , es ist nicht findall

Konark Modi
quelle
4
Dies funktioniert nur für genaue Übereinstimmungen. <.. class="stylelistrow">passt aber nicht <.. class="stylelistrow button">.
Wernight
11

So finden Sie Elemente nach Klasse

Ich habe Probleme beim Parsen von HTML-Elementen mit dem Attribut "class" mithilfe von Beautifulsoup.

Sie können leicht nach einer Klasse finden, aber wenn Sie nach dem Schnittpunkt zweier Klassen suchen möchten, ist es etwas schwieriger.

Aus der Dokumentation (Hervorhebung hinzugefügt):

Wenn Sie nach Tags suchen möchten, die zwei oder mehr CSS-Klassen entsprechen, sollten Sie einen CSS-Selektor verwenden:

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

Um klar zu sein, werden hier nur die p-Tags ausgewählt, die sowohl Strikeout als auch Body Class sind.

Um den Schnittpunkt von any in einer Reihe von Klassen zu finden (nicht den Schnittpunkt, sondern die Vereinigung), können Sie dem class_Schlüsselwortargument (ab 4.1.2) eine Liste geben :

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) 

Beachten Sie auch, dass findAll von camelCase in pythonischer umbenannt wurde find_all.

Aaron Hall
quelle
11

CSS-Selektoren

Einzelklasse erstes Match

soup.select_one('.stylelistrow')

Liste der Übereinstimmungen

soup.select('.stylelistrow')

zusammengesetzte Klasse (dh UND eine andere Klasse)

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

Leerzeichen in zusammengesetzten Klassennamen werden z. B. class = stylelistrow otherclassnamedurch "." Ersetzt. Sie können weiterhin Klassen hinzufügen.

Liste der Klassen (ODER - entspricht der vorhandenen Klasse

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

bs4 4.7.1 +

Bestimmte Klasse, innerTextdie eine Zeichenfolge enthält

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

Bestimmte Klasse mit einem bestimmten untergeordneten Element, z. B. aTag

soup.select_one('.stylelistrow:has(a)')
soup.select('.stylelistrow:has(a)')
QHarr
quelle
5

Ab BeautifulSoup 4+,

Wenn Sie einen einzelnen Klassennamen haben, können Sie den Klassennamen einfach wie folgt übergeben:

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

Oder wenn Sie mehr als einen Klassennamen haben, übergeben Sie einfach die Liste der Klassennamen als Parameter wie:

mydivs = soup.find_all('div', ['class1', 'class2'])
Shivam Shah
quelle
3

Versuchen Sie zuerst zu überprüfen, ob das div ein Klassenattribut hat, wie folgt:

soup = BeautifulSoup(sdata)
mydivs = soup.findAll('div')
for div in mydivs:
    if "class" in div:
        if (div["class"]=="stylelistrow"):
            print div
Miauen
quelle
1
Das geht nicht Ich denke, Ihr Ansatz war richtig, aber die 4. Zeile funktioniert nicht wie beabsichtigt.
Neo
1
Ah, ich dachte, div funktioniert wie ein Wörterbuch, ich kenne Beautiful Soup nicht wirklich, also war es nur eine Vermutung.
Mew
3

Dies funktioniert für mich, um auf das Klassenattribut zuzugreifen (auf beautifulsoup 4, entgegen der Dokumentation). Der KeyError enthält eine Liste, die nicht als Wörterbuch zurückgegeben wird.

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

Folgendes hat bei mir funktioniert

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

Das hat bei mir funktioniert:

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

Alternativ können wir lxml verwenden, es unterstützt xpath und ist sehr schnell!

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
quelle
0

Das sollte funktionieren:

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

Andere Antworten haben bei mir nicht funktioniert.

In anderen Antworten findAllwird das für das Suppenobjekt selbst verwendet, aber ich brauchte eine Möglichkeit, Objekte nach Objekten innerhalb eines bestimmten Elements zu finden, die aus dem Objekt extrahiert wurden, das ich nach dem Ausführen erhalten hatte findAll.

Wenn Sie versuchen, in verschachtelten HTML-Elementen nach Objekten nach Klassennamen zu suchen, versuchen Sie es unten -

# 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

Zu beachtende Punkte:

  1. Ich definiere die Suche nicht explizit als "Klassen" -Attribut findAll("li", {"class": "song_item"}), da dies das einzige Attribut ist, nach dem ich suche, und standardmäßig nach Klassenattributen gesucht wird, wenn Sie nicht ausschließlich angeben, nach welchem ​​Attribut Sie suchen möchten.

  2. Wenn Sie ein findAlloder findausführen, gehört das resultierende Objekt zur Klasse, bs4.element.ResultSetdie eine Unterklasse von ist list. Sie können alle Methoden ResultSetinnerhalb einer beliebigen Anzahl verschachtelter Elemente (sofern diese vom Typ sind ResultSet) verwenden, um eine Suche durchzuführen oder alle zu finden.

  3. Meine BS4-Version - 4.9.1, Python-Version - 3.8.1

ZeroFlex
quelle
0

Folgendes sollte funktionieren

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

Ersetzen Sie 'totalcount' durch Ihren Klassennamen und 'span' durch das gesuchte Tag. Wenn Ihre Klasse mehrere Namen mit Leerzeichen enthält, wählen Sie einfach einen aus und verwenden Sie.

PS Hiermit wird das erste Element mit bestimmten Kriterien gefunden. Wenn Sie alle Elemente finden möchten, ersetzen Sie 'find' durch 'find_all'.

Hari Sudhan
quelle