Bagaimana menemukan elemen berdasarkan kelas

386

Saya mengalami masalah dalam menguraikan elemen HTML dengan atribut "class" menggunakan Beautifulsoup. Kode terlihat seperti ini

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

Saya mendapatkan kesalahan pada baris yang sama "setelah" skrip selesai.

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'

Bagaimana saya menyingkirkan kesalahan ini?

Neo
sumber

Jawaban:

646

Anda dapat mempersempit pencarian Anda hanya untuk menemukan divs dengan kelas yang diberikan menggunakan BS3:

mydivs = soup.findAll("div", {"class": "stylelistrow"})
Klaus Byskov Pedersen
sumber
@ Klaus- bagaimana jika saya ingin menggunakan findAll?
1
Terima kasih untuk ini. Ini bukan hanya untuk @class tetapi untuk apa pun.
Prageeth
41
Ini hanya berfungsi untuk pencocokan tepat. <.. class="stylelistrow">cocok tapi tidak <.. class="stylelistrow button">.
Wernight
4
@pyCthon Lihat jawaban untuk @jmunsch, BS sekarang mendukung class_yang berfungsi dengan baik.
Wernight
25
Pada beautifulsoup4, findAll sekarang find_all
Neoecos
273

Dari dokumentasi:

Pada Beautiful Soup 4.1.2, Anda dapat mencari berdasarkan kelas CSS menggunakan argumen kata kunci class_ :

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

Yang dalam hal ini adalah:

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

Ini juga akan bekerja untuk:

soup.find_all("div", class_="stylelistrowone stylelistrowtwo")
jmunsch
sumber
5
Anda juga dapat menggunakan daftar: soup.find_all("a", ["stylelistrowone", "stylelistrow"])Lebih aman jika Anda tidak memiliki banyak kelas.
Nuno André
4
Ini harus menjadi jawaban yang diterima, itu lebih tepat dan ringkas daripada alternatif.
goncalopp
1
Tambahan @ jawaban NunoAndré untuk BeautifulSoup 3: soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']}).
Brad
55

Pembaruan: 2016 Dalam versi terbaru beautifulsoup, metode 'findAll' telah diubah namanya menjadi 'find_all'. Tautan ke dokumentasi resmi

Daftar nama metode berubah

Maka jawabannya adalah

soup.find_all("html_element", class_="your_class_name")
tuan
sumber
18

Khusus untuk BeautifulSoup 3:

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

Akan menemukan semua ini:

<div class="stylelistrow">
<div class="stylelistrow button">
<div class="button stylelistrow">
FlipMcF
sumber
Mengapa tidak mencari kembali ('. * Stylelistrow. *', X)?
rjurney
karena dengan begitu stylelistrow2 akan cocok. Komentar yang lebih baik adalah "mengapa tidak menggunakan string.find () alih-alih kembali?"
FlipMcF
2
lambda x: 'stylelistrow' in x.split()sederhana dan indah
fferri
Dan saya benci regex. Terima kasih! (memperbarui jawaban) | menjaga 'x dan' untuk menguji Tidak Ada
FlipMcF
16

Jalan lurus ke depan adalah:

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

Pastikan Anda mengambil casing findAll , bukan findall

Konark Modi
sumber
4
Ini hanya berfungsi untuk pencocokan tepat. <.. class="stylelistrow">cocok tapi tidak <.. class="stylelistrow button">.
Wernight
11

Bagaimana menemukan elemen berdasarkan kelas

Saya mengalami masalah dalam menguraikan elemen html dengan atribut "class" menggunakan Beautifulsoup.

Anda dapat dengan mudah menemukan dengan satu kelas, tetapi jika Anda ingin menemukan dengan persimpangan dua kelas, itu sedikit lebih sulit,

Dari dokumentasi (penekanan ditambahkan):

Jika Anda ingin mencari tag yang cocok dengan dua atau lebih kelas CSS, Anda harus menggunakan pemilih CSS:

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

Agar lebih jelas, ini hanya memilih tag p yang keduanya strikeout dan kelas tubuh.

Untuk menemukan persimpangan dari setiap kelas (bukan persimpangan, tetapi gabungan), Anda dapat memberikan daftar ke class_argumen kata kunci (pada 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) 

Perhatikan juga bahwa findAll telah diubah namanya dari camelCase menjadi lebih Pythonic find_all.

Aaron Hall
sumber
11

Penyeleksi CSS

pertandingan pertama kelas tunggal

soup.select_one('.stylelistrow')

daftar kecocokan

soup.select('.stylelistrow')

kelas majemuk (yaitu DAN kelas lain)

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

Spasi dalam nama kelas majemuk misalnya class = stylelistrow otherclassnamediganti dengan "." Anda dapat terus menambahkan kelas.

daftar kelas (ATAU - cocokkan yang mana saja yang hadir

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

bs4 4.7.1 +

Kelas khusus yang innerTextberisi string

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

Kelas khusus yang memiliki elemen turunan tertentu misalnya atag

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

Pada BeautifulSoup 4+,

Jika Anda memiliki nama kelas tunggal, Anda bisa meneruskan nama kelas sebagai parameter seperti:

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

Atau jika Anda memiliki lebih dari satu nama kelas, cukup berikan daftar nama kelas sebagai parameter seperti:

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

Coba periksa apakah div memiliki atribut class terlebih dahulu, seperti ini:

soup = BeautifulSoup(sdata)
mydivs = soup.findAll('div')
for div in mydivs:
    if "class" in div:
        if (div["class"]=="stylelistrow"):
            print div
Mengeong
sumber
1
Itu tidak berhasil. Saya kira pendekatan Anda benar, tetapi baris ke-4 tidak berfungsi sebagaimana mestinya.
Neo
1
Ah saya pikir div berfungsi seperti kamus, saya tidak terlalu mengenal Beautiful Soup jadi itu hanya tebakan.
Mew
3

Ini berfungsi bagi saya untuk mengakses atribut kelas (pada beautifulsoup 4, bertentangan dengan apa yang dikatakan dokumentasi). KeyError datang daftar yang dikembalikan bukan kamus.

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

berikut ini bekerja untuk saya

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

Ini bekerja untuk saya:

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

Atau kita dapat menggunakan lxml, mendukung xpath dan sangat cepat!

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

Ini seharusnya bekerja:

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

Jawaban lain tidak berhasil untuk saya.

Dalam jawaban lain, findAllini digunakan pada objek sup itu sendiri, tetapi saya membutuhkan cara untuk melakukan pencarian berdasarkan nama kelas pada objek di dalam elemen tertentu yang diekstraksi dari objek yang saya peroleh setelah melakukan findAll.

Jika Anda mencoba melakukan pencarian di dalam elemen HTML bersarang untuk mendapatkan objek dengan nama kelas, coba di bawah ini -

# 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

Poin yang perlu diperhatikan:

  1. Saya tidak secara eksplisit mendefinisikan pencarian menjadi atribut 'kelas' findAll("li", {"class": "song_item"}), karena itu adalah satu-satunya atribut yang saya cari dan itu akan secara default mencari atribut kelas jika Anda tidak secara eksklusif memberi tahu atribut yang ingin Anda temukan.

  2. Ketika Anda melakukan findAllatau find, objek yang dihasilkan adalah kelas bs4.element.ResultSetyang merupakan subkelas dari list. Anda dapat menggunakan semua metode ResultSetdi dalam sejumlah elemen bersarang (asalkan bertipe ResultSet) untuk menemukan atau menemukan semuanya.

  3. Versi BS4 saya - 4.9.1, Versi Python - 3.8.1

ZeroFlex
sumber
0

Berikut ini harus bekerja

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

ganti 'totalcount' dengan nama kelas Anda dan 'span' dengan tag yang Anda cari. Juga, jika kelas Anda berisi banyak nama dengan spasi, cukup pilih satu dan gunakan.

PS Ini menemukan elemen pertama dengan kriteria yang diberikan. Jika Anda ingin menemukan semua elemen, ganti 'temukan' dengan 'find_all'.

hari sudhan
sumber