วิธีการค้นหาองค์ประกอบตามชั้นเรียน


386

ฉันมีปัญหาในการแยกวิเคราะห์องค์ประกอบ HTML ด้วยแอตทริบิวต์ "class" โดยใช้ Beautifulsoup รหัสมีลักษณะเช่นนี้

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

ฉันพบข้อผิดพลาดในบรรทัดเดียวกัน "หลังจาก" สคริปต์เสร็จสิ้น

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'

ฉันจะกำจัดข้อผิดพลาดนี้ได้อย่างไร

คำตอบ:


646

คุณสามารถปรับแต่งการค้นหาของคุณเพื่อค้นหา div เหล่านั้นด้วยคลาสที่กำหนดโดยใช้ BS3:

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

@ Klaus - ถ้าฉันต้องการใช้ findAll แทนล่ะ

1
ขอบคุณสำหรับสิ่งนี้. มันไม่ได้มีไว้สำหรับ @class เท่านั้น
prageeth

41
สิ่งนี้ใช้ได้กับการแข่งขันที่แน่นอนเท่านั้น แต่ไม่ตรงกับ<.. class="stylelistrow"> <.. class="stylelistrow button">
Wernight

4
@pyCthon ดูคำตอบสำหรับ @jmunsch ตอนนี้ BS รองรับการclass_ทำงานที่เหมาะสม
Wernight

25
ในฐานะของ beautifulsoup4 ตอนนี้ findAll อยู่ในขณะนี้ find_all
Neoecos

273

จากเอกสาร:

จาก Beautiful Soup 4.1.2 คุณสามารถค้นหาโดยใช้คลาส CSS โดยใช้อาร์กิวเมนต์คำหลัก class_ :

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

ซึ่งในกรณีนี้จะเป็น:

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

มันจะทำงานสำหรับ:

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

5
คุณสามารถใช้รายการได้เช่นกัน: soup.find_all("a", ["stylelistrowone", "stylelistrow"])จะปลอดภัยกว่าถ้าคุณไม่มีหลายคลาส
Nuno André

4
นี่ควรเป็นคำตอบที่ยอมรับได้ทั้งถูกต้องและรัดกุมกว่าทางเลือก
goncalopp

1
อาหารเสริมเพื่อ @ คำตอบNunoAndréสำหรับ BeautifulSoup soup.findAll("a", {'class':['stylelistrowone', 'stylelistrow']})3:
แบรด


18

เฉพาะกับ BeautifulSoup 3:

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

จะพบทั้งหมดเหล่านี้:

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

ทำไมไม่ค้นหาใหม่ ('. * stylelistrow. *', x)
rjurney

เพราะสไตลิสลิสโตว์ 2 จะจับคู่กัน ความคิดเห็นที่ดีกว่าคือ "ทำไมไม่ใช้ string.find () แทนที่จะเป็น"
FlipMcF

2
lambda x: 'stylelistrow' in x.split()เรียบง่ายและสวยงาม
เฟเฟอร์รี

และฉันเกลียด regexes ขอบคุณ! (อัปเดตคำตอบ) | รักษา 'x และ' เพื่อทดสอบสำหรับไม่มี
FlipMcF

16

ทางตรงไปข้างหน้าจะเป็น:

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

ตรวจสอบให้แน่ใจว่าคุณใช้ปลอกของfindAllไม่ใช่findall


4
สิ่งนี้ใช้ได้กับการแข่งขันที่แน่นอนเท่านั้น แต่ไม่ตรงกับ<.. class="stylelistrow"> <.. class="stylelistrow button">
Wernight

11

วิธีการค้นหาองค์ประกอบตามชั้นเรียน

ฉันมีปัญหาในการแยกวิเคราะห์องค์ประกอบ HTML ด้วยแอตทริบิวต์ "class" โดยใช้ Beautifulsoup

คุณสามารถค้นหาโดยชั้นเรียนได้อย่างง่ายดาย แต่ถ้าคุณต้องการค้นหาโดยจุดตัดของสองชั้นมันจะยากขึ้นอีกนิด

จากเอกสาร (เน้นเพิ่ม):

หากคุณต้องการค้นหาแท็กที่ตรงกับคลาส CSS สองคลาสขึ้นไปคุณควรใช้ตัวเลือก CSS:

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

เพื่อความชัดเจนนี่เป็นการเลือกเฉพาะแท็ก p ที่เป็นทั้งขีดฆ่าและคลาสบอดี้

หากต้องการค้นหาจุดตัดของชุดใด ๆในชุดของคลาส (ไม่ใช่จุดตัด แต่เป็นแบบร่วม) คุณสามารถให้รายการกับclass_อาร์กิวเมนต์ของคำหลัก (เช่น 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) 

นอกจากนี้ทราบว่า findall ได้ถูกเปลี่ยนชื่อจาก CamelCase ไป find_allPythonic


11

CSS selectors

ชั้นเดียวนัดแรก

soup.select_one('.stylelistrow')

รายการที่ตรงกัน

soup.select('.stylelistrow')

ชั้นผสม (เช่นและอีกชั้นหนึ่ง)

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

ช่องว่างในชื่อคลาสผสมเช่นclass = stylelistrow otherclassnameถูกแทนที่ด้วย "." คุณสามารถเพิ่มคลาสต่อไปได้

รายการของคลาส (หรือ - จับคู่แบบใดก็ได้ที่มีอยู่)

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

bs4 4.7.1 +

คลาสเฉพาะที่innerTextประกอบด้วยสตริง

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

คลาสที่เฉพาะเจาะจงซึ่งมีองค์ประกอบลูกบางอย่างเช่นaแท็ก

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

5

ตั้งแต่ BeautifulSoup 4+

หากคุณมีชื่อคลาสเดียวคุณสามารถส่งชื่อคลาสเป็นพารามิเตอร์เช่น:

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

หรือถ้าคุณมีชื่อคลาสมากกว่าหนึ่งชื่อให้ส่งรายการชื่อคลาสเป็นพารามิเตอร์เช่น:

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

3

ลองตรวจสอบว่า div มีแอตทริบิวต์ class ก่อนเช่นนี้หรือไม่:

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

1
ไม่ได้ผล ฉันเดาว่าวิธีการของคุณถูกต้อง แต่บรรทัดที่ 4 ไม่ทำงานตามที่ตั้งใจไว้
Neo

1
ฉันคิดว่า div ทำงานเหมือนพจนานุกรมฉันไม่คุ้นเคยกับ Beautiful Soup มากนักดังนั้นมันจึงเป็นเพียงการคาดเดา
เหมียว

3

สิ่งนี้ใช้ได้สำหรับฉันในการเข้าถึงแอตทริบิวต์ class (บน beautifulsoup 4 ตรงข้ามกับที่เอกสารระบุ) KeyError มีรายการที่ส่งคืนไม่ใช่พจนานุกรม

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


1

สิ่งนี้ใช้ได้กับฉัน:

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

1

หรือเราสามารถใช้ lxml ก็รองรับ xpath และเร็วมาก!

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

คำตอบอื่น ๆ ไม่ได้ผลสำหรับฉัน

ในคำตอบอื่น ๆfindAllจะถูกนำมาใช้ในวัตถุซุปตัวเอง findAllแต่ผมจำเป็นต้องมีวิธีการทำโดยพบชื่อชั้นบนวัตถุภายในองค์ประกอบเฉพาะสกัดจากวัตถุที่ผมได้รับหลังจากการทำ

หากคุณพยายามที่จะค้นหาภายในองค์ประกอบ HTML ซ้อนกันเพื่อรับวัตถุตามชื่อชั้นลองด้านล่าง -

# 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

จุดที่ควรทราบ:

  1. ฉันไม่ได้นิยามการค้นหาอย่างชัดเจนว่าเป็นแอตทริบิวต์ 'class' findAll("li", {"class": "song_item"})เนื่องจากเป็นคุณลักษณะเดียวที่ฉันกำลังค้นหาและจะเป็นการค้นหาแอตทริบิวต์ class โดยค่าเริ่มต้นหากคุณไม่ได้บอกเฉพาะคุณลักษณะที่คุณต้องการค้นหา

  2. เมื่อคุณทำfindAllหรือfindวัตถุที่เกิดขึ้นเป็นของชั้นbs4.element.ResultSetซึ่งเป็น subclass listของ คุณสามารถใช้วิธีการทั้งหมดResultSetภายในองค์ประกอบที่ซ้อนกันจำนวนเท่าใดก็ได้ (ตราบใดที่เป็นประเภทResultSet) เพื่อทำการค้นหาหรือค้นหาทั้งหมด

  3. รุ่น BS4 ของฉัน - 4.9.1, Python เวอร์ชั่น - 3.8.1


0

ต่อไปนี้ควรทำงาน

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

แทนที่ 'totalcount' ด้วยชื่อคลาสของคุณและ 'span' ด้วยแท็กที่คุณกำลังมองหา นอกจากนี้หากชั้นเรียนของคุณมีหลายชื่อพร้อมช่องว่างเพียงแค่เลือกชื่อและใช้

ป.ล. นี้พบองค์ประกอบแรกที่มีเกณฑ์ที่กำหนด หากคุณต้องการค้นหาองค์ประกอบทั้งหมดให้แทนที่ 'ค้นหา' ด้วย 'find_all'

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.