Hoe elementen per klasse te vinden

Ik heb problemen met het ontleden van HTML-elementen met het kenmerk “class” met Beautifulsoup. De code ziet er zo uit

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

Ik krijg een foutmelding op dezelfde regel “nadat” het script is voltooid.

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'

Hoe kom ik van deze fout af?


Antwoord 1, autoriteit 100%

Je kunt je zoekopdracht verfijnen om alleen die div’s met een bepaalde klasse te vinden met BS3:

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

Antwoord 2, autoriteit 44%

Uit de documentatie:

Vanaf Beautiful Soup 4.1.2 kan zoeken op CSS-klasse met behulp van het trefwoordargumentclass_:

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

Wat in dit geval zou zijn:

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

Het zou ook werken voor:

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

Antwoord 3, autoriteit 9%

Update: 2016
In de nieuwste versie van beautifulsoup is de methode ‘findAll’ hernoemd naar
‘vind alle’. Link naar officiële documentatie

Daarom is het antwoord

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

Antwoord 4, autoriteit 3%

Specifiek voor BeautifulSoup 3:

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

Zal deze allemaal vinden:

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

Antwoord 5, autoriteit 3%

CSS-kiezers

eerste wedstrijd in één klas

soup.select_one('.stylelistrow')

lijst met overeenkomsten

soup.select('.stylelistrow')

samengestelde klasse (d.w.z. EN een andere klasse)

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

Spaties in namen van samengestelde klassen, bijv. class = stylelistrow otherclassnameworden vervangen door “.”. Je kunt doorgaan met het toevoegen van lessen.

lijst met lessen (OF – match met de aanwezige)

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

bs4 4.7.1 +

Specifieke klasse waarvan innerTexteen tekenreeks bevat

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

NB

soupsieve 2.1.0 + vanaf december 2020

NIEUW: om conflicten met toekomstige CSS-specificaties te voorkomen
wijzigingen, beginnen niet-standaard pseudo-klassen nu met de :-soep-
voorvoegsel. Als gevolg hiervan zal :contains() nu bekend staan als
:-soup-contains(), hoewel voor een tijd de verouderde vorm van
:contains() is nog steeds toegestaan met een waarschuwing dat gebruikers dit moeten doen
migreer naar :-soup-contains().

NIEUW: Nieuwe niet-standaard pseudo-klasse toegevoegd:-soep-bevat-eigen() die
werkt vergelijkbaar met :-soup-contains() behalve dat het alleen kijkt naar
tekstknooppunten die direct zijn gekoppeld aan het element met het huidige bereik en
niet zijn nakomelingen.

Specifieke klasse die een bepaald onderliggend element heeft, b.v. a-tag

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

Antwoord 6, autoriteit 2%

Een ongecompliceerde manier zou zijn:

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

Zorg ervoor dat u de behuizing van findAllverwijdert, het is niet findall


Antwoord 7, autoriteit 2%

Hoe elementen per klasse te vinden

Ik heb problemen met het ontleden van html-elementen met het kenmerk “class” met Beautifulsoup.

Je kunt gemakkelijk zoeken op één klasse, maar als je wilt zoeken op het snijpunt van twee klassen, is het iets moeilijker,

Uit de documentatie(nadruk toegevoegd):

Als u wilt zoeken naar tags die overeenkomen met twee of meerCSS-klassen, moet u een CSS-selector gebruiken:

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

Voor alle duidelijkheid, dit selecteert alleen de p-tags die zowel strikeout als body class zijn.

Om het snijpunt van elkein een reeks klassen (niet het snijpunt, maar de unie) te vinden, kun je een lijst geven aan het trefwoordargument class_( vanaf 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) 

Houd er rekening mee dat findAll is hernoemd van de camelCase naar het meer Pythonische find_all.


Antwoord 8

Vanaf BeautifulSoup 4+ ,

Als je een enkele klassenaam hebt, kun je de klassenaam gewoon als parameter doorgeven, zoals:

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

Of als je meer dan één klassenaam hebt, geef je de lijst met klassenamen door als parameter zoals :

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

Antwoord 9

Probeer te controleren of de div eerst een klasse kenmerk heeft, zoals dit:

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

Antwoord 10

Dit werkt voor mij om toegang te krijgen tot het kenmerk Class (op Beautifulsoup 4, in tegenstelling tot wat de documentatie zegt). De KeyErError wordt geleverd met een lijst die niet een woordenboek wordt geretourneerd.

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

Antwoord 11

Het volgende werkte voor mij

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

Antwoord 12

Gebruik class_=Als u element (en) wilt vinden zonder de HTML-tag te vermelden.

Voor een enkel element:

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

Voor meerdere elementen:

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

Antwoord 13

Andere antwoorden werkten niet voor mij.

In andere antwoorden De findAllwordt gebruikt op het soepobject zelf, maar ik had een manier nodig om een ​​vondst te doen bij de naam van de klas op objecten in een specifiek element dat wordt geëxtraheerd uit het doel dat ik na het doen is geëxtraheerd findAll.

Als u probeert een zoekopdracht binnen geneste HTML-elementen te doen om objecten per klas te krijgen, probeert u hieronder –

# 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

Punten om op te merken:

  1. Ik definieer niet expliciet de zoekopdracht om op ‘Class’ kenmerk findAll("li", {"class": "song_item"}), omdat het het enige attribuut is, omdat het het enige attribuut is Ik ben op zoek naar en het zal standaard zoeken naar classattribuut als u niet uitsluitend vertelt welk attribuut u wilt vinden.

  2. Wanneer u een findAllof find, is het resulterende object van klasse bs4.element.ResultSetwat een subklasse is van list. U kunt alle methoden van ResultSet, binnen een willekeurig aantal geneste elementen (zolang ze zijn van het type ResultSet) om een ​​vondst te doen of alles te vinden.

  3. My BS4-versie – 4.9.1, Python-versie – 3.8.1


Antwoord 14

Betreffende @ wernight’s opmerking op de Top antwoord Over gedeeltelijke matching …

U kunt gedeeltelijk overeenkomen:

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

met gazpacho :

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

Beide worden vastgelegd en geretourneerd als een lijst met Soup-objecten.


Antwoord 15

Dit werkte voor mij:

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

Antwoord 16

Dit zou moeten werken:

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

Antwoord 17

Als alternatief kunnen we lxml gebruiken, het ondersteunt xpath en erg snel!

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

Antwoord 18

Het volgende zou moeten werken

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

vervang ‘totalcount’ door je klasnaam en ‘span’ door de tag die je zoekt. Als je klas meerdere namen met spatie bevat, kies er dan gewoon een en gebruik.

P.S. Dit vindt het eerste element met gegeven criteria. Als je alle elementen wilt vinden, vervang dan ‘find’ door ‘find_all’.


Antwoord 19

enkele

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

meerdere

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

Other episodes