Cách tìm các phần tử theo lớp


386

Tôi gặp sự cố khi phân tích các phần tử HTML bằng thuộc tính "class" bằng Beautifulsoup. Mã trông như thế này

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

Tôi gặp lỗi trên cùng một dòng "sau khi" tập lệnh kết thúc.

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'

Làm thế nào để tôi thoát khỏi lỗi này?

Câu trả lời:


646

Bạn có thể tinh chỉnh tìm kiếm của mình để chỉ tìm những div đó với một lớp nhất định bằng BS3:

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

@ Klaus- nếu tôi muốn sử dụng findAll thì sao?

1
Cám ơn vì cái này. Nó không chỉ dành cho @ class mà còn cho bất cứ điều gì.
prageeth

41
Điều này chỉ hoạt động cho các trận đấu chính xác. <.. class="stylelistrow">phù hợp nhưng không <.. class="stylelistrow button">.
Wernight

4
@pyCthon Xem câu trả lời cho @jmunsch, BS hiện hỗ trợ class_hoạt động đúng.
Wernight

25
Kể từ beautifulsoup4, findAll hiện là find_all
Neoecos

273

Từ tài liệu:

Kể từ Beautiful Soup 4.1.2, bạn có thể tìm kiếm theo lớp CSS bằng cách sử dụng đối số từ khóa class_ :

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

Mà trong trường hợp này sẽ là:

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

Nó cũng sẽ làm việc cho:

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

5
Bạn cũng có thể sử dụng danh sách: soup.find_all("a", ["stylelistrowone", "stylelistrow"])Sẽ an toàn hơn nếu bạn không có nhiều lớp.
Nuno André

4
Đây phải là câu trả lời được chấp nhận, nó vừa chính xác vừa súc tích hơn các lựa chọn thay thế.
goncalopp

1
Bổ sung cho câu trả lời của @ NunoAndré cho BeautifulSoup 3 : soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']}).
Brad


18

Cụ thể cho BeautifulSoup 3:

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

Sẽ tìm thấy tất cả những điều này:

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

Tại sao không tìm kiếm lại ('. * Stylelistrow. *', X)?
rjurney

bởi vì sau đó stylelistrow2 sẽ khớp. Nhận xét tốt hơn là "tại sao không sử dụng chuỗi.find () thay vì re?"
FlipMcF

2
lambda x: 'stylelistrow' in x.split()đơn giản và đẹp
fferri

Và tôi ghét regexes. Cảm ơn bạn! (cập nhật câu trả lời) | giữ 'x và' để kiểm tra Không có gì
FlipMcF

16

Một cách thẳng về phía trước sẽ là:

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

Hãy chắc chắn rằng bạn lấy vỏ của find ALL , không phải là findall


4
Điều này chỉ hoạt động cho các trận đấu chính xác. <.. class="stylelistrow">phù hợp nhưng không <.. class="stylelistrow button">.
Wernight

11

Cách tìm các phần tử theo lớp

Tôi gặp sự cố khi phân tích các phần tử html bằng thuộc tính "class" bằng Beautifulsoup.

Bạn có thể dễ dàng tìm thấy bởi một lớp, nhưng nếu bạn muốn tìm bởi giao điểm của hai lớp, điều đó khó hơn một chút,

Từ tài liệu (nhấn mạnh thêm):

Nếu bạn muốn tìm kiếm các thẻ khớp với hai hoặc nhiều lớp CSS, bạn nên sử dụng bộ chọn CSS:

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

Để rõ ràng, điều này chỉ chọn các thẻ p là cả tấn công và lớp cơ thể.

Để tìm giao điểm của bất kỳ trong một tập hợp các lớp (không phải giao điểm, mà là liên kết), bạn có thể đưa ra một danh sách cho class_đối số từ khóa (kể từ 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) 

Cũng lưu ý rằng findAll đã được đổi tên từ camelCase thành Pythonic hơn find_all.


11

Bộ chọn CSS

trận đấu hạng nhất

soup.select_one('.stylelistrow')

danh sách các trận đấu

soup.select('.stylelistrow')

lớp ghép (tức là VÀ lớp khác)

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

Dấu cách trong tên lớp ghép, ví dụ: class = stylelistrow otherclassnameđược thay thế bằng ".". Bạn có thể tiếp tục thêm các lớp.

danh sách các lớp (HOẶC - phù hợp với bất kỳ hiện tại

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

bs4 4.7.1 +

Lớp cụ thể có innerTextchứa một chuỗi

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

Lớp cụ thể có một phần tử con nhất định, ví dụ: athẻ

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

5

Kể từ BeautifulSoup 4+,

Nếu bạn có một tên lớp duy nhất, bạn có thể chuyển tên lớp thành tham số như:

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

Hoặc nếu bạn có nhiều tên lớp, chỉ cần chuyển danh sách tên lớp làm tham số như:

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

3

Hãy thử kiểm tra xem div có thuộc tính lớp trước không, như sau:

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

1
Điều đó không hiệu quả. Tôi đoán cách tiếp cận của bạn là đúng, nhưng dòng thứ 4 không hoạt động như dự định.
Neo

1
Ah tôi nghĩ div làm việc như một cuốn từ điển, tôi không thực sự quen thuộc với Beautiful Soup nên nó chỉ là một phỏng đoán.
Mew

3

Điều này hoạt động để tôi truy cập thuộc tính lớp (trên beautifulsoup 4, trái với những gì tài liệu nói). KeyError có một danh sách được trả về không phải là từ điển.

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

3

những điều sau đây làm việc cho tôi

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

1

Điều này làm việc cho tôi:

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

1

Ngoài ra, chúng tôi có thể sử dụng lxml, nó hỗ trợ xpath và rất nhanh!

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

Điều này sẽ làm việc:

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

0

Các câu trả lời khác không làm việc cho tôi.

Trong các câu trả lời khác, findAllnó đang được sử dụng trên chính đối tượng súp, nhưng tôi cần một cách để tìm một tên lớp trên các đối tượng bên trong một phần tử cụ thể được trích xuất từ ​​đối tượng tôi thu được sau khi thực hiện findAll.

Nếu bạn đang cố thực hiện tìm kiếm bên trong các phần tử HTML lồng nhau để lấy các đối tượng theo tên lớp, hãy thử bên dưới -

# 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

Điểm cần lưu ý:

  1. Tôi không xác định rõ ràng tìm kiếm thuộc tính 'class' findAll("li", {"class": "song_item"}), vì đó là thuộc tính duy nhất tôi đang tìm kiếm và theo mặc định nó sẽ tìm kiếm thuộc tính lớp nếu bạn không nói riêng về thuộc tính nào bạn muốn tìm.

  2. Khi bạn thực hiện một findAllhoặc find, đối tượng kết quả là của lớp bs4.element.ResultSetlà một lớp con của list. Bạn có thể sử dụng tất cả các phương thức ResultSet, bên trong bất kỳ số lượng phần tử lồng nhau nào (miễn là chúng thuộc loại ResultSet) để tìm hoặc tìm tất cả.

  3. Phiên bản BS4 của tôi - 4.9.1, phiên bản Python - 3.8.1


0

Sau đây nên làm việc

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

thay thế 'tổng số' bằng tên lớp của bạn và 'span' bằng thẻ bạn đang tìm kiếm. Ngoài ra, nếu lớp của bạn chứa nhiều tên có khoảng trắng, chỉ cần chọn một tên và sử dụng.

PS Điều này tìm thấy phần tử đầu tiên với các tiêu chí nhất định. Nếu bạn muốn tìm tất cả các yếu tố thì thay thế 'find' bằng 'find_all'.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.