如何使用BeautifulSoup从父标签中选择特定子标签并抓取数据?
问题:抓取class为val的div文本内容
现有HTML结构中,每个class为b-card的div包含两个class为val的子div,分别对应「总项目数」和「进行中项目数」。目前已能成功抓取企业名称,但无法准确获取这两个数值,现有代码在处理count-wrap时定位逻辑有误。
目标HTML片段
<div class="b-card"> <div class="builder-exp-wrap"> <a class="no-ajaxy img-wrap js-rc-link" data-href="/puravankara-limited-100046"> <img alt="Images for Logo of Puravankara" src="https://im.proptiger.com/3/100046/13/puravankara-4491843.jpeg?width=155&height=50"/> </a> <div class="builder-details-wrap"> <a class="no-ajaxy builder-name put-ellipsis js-b-card" data-builderid="100046" href="/puravankara-limited-100046" target="_blank"> Puravankara Limited </a> </div> </div> <div class="b-dtls"> <div class="count-wrap one"> <div class="circle"> <div class="val"> 99 </div> </div> <div class="lbl"> Total Projects </div> </div> <div class="count-wrap"> <div class="circle"> <div class="val"> 36 </div> </div> <div class="lbl"> Ongoing Projects </div> </div> </div> </div>
用户现有代码
from bs4 import BeautifulSoup import requests main_url="https://www.proptiger.com/bangalore/all-builders?page=1" main_url_html=BeautifulSoup(requests.get(main_url).text,"html.parser") for bcard in main_url_html.find_all('div',class_='b-card'): bcard_CompanyName=bcard.find('div',class_='builder-details-wrap') bcard_CompanyName=bcard_CompanyName.a.text bcard_OngoingProjs=bcard.find('div',class_='count-wrap') bcard_OngoingProjs=bcard_OngoingProjs.div.div.text
解决方案
方法1:直接定位class为val的元素
跳过逐层嵌套的复杂定位,直接在当前b-card下抓取所有val类元素,再按顺序提取对应数值:
for bcard in main_url_html.find_all('div', class_='b-card'): # 抓取企业名称 company_name = bcard.find('div', class_='builder-details-wrap').a.text.strip() # 抓取所有val类元素 val_elements = bcard.find_all('div', class_='val') total_projects = val_elements[0].text.strip() # 第一个val对应总项目数 ongoing_projects = val_elements[1].text.strip() # 第二个val对应进行中项目数 print(f"企业名称:{company_name}") print(f"总项目数:{total_projects}") print(f"进行中项目数:{ongoing_projects}")
方法2:按count-wrap的位置精准定位
通过find_all获取两个count-wrap元素,再分别定位内部的val:
for bcard in main_url_html.find_all('div', class_='b-card'): company_name = bcard.find('div', class_='builder-details-wrap').a.text.strip() # 获取所有count-wrap容器 count_wraps = bcard.find_all('div', class_='count-wrap') # 第一个count-wrap下的val是总项目数 total_projects = count_wraps[0].find('div', class_='val').text.strip() # 第二个count-wrap下的val是进行中项目数 ongoing_projects = count_wraps[1].find('div', class_='val').text.strip() print(f"企业名称:{company_name}") print(f"总项目数:{total_projects}") print(f"进行中项目数:{ongoing_projects}")
方法3:使用CSS选择器简化代码
利用BeautifulSoup的CSS选择器支持,用更简洁的语法定位目标元素:
for bcard in main_url_html.select('div.b-card'): company_name = bcard.select_one('div.builder-details-wrap a').text.strip() # 通过.one类区分总项目数的容器 total_projects = bcard.select_one('div.count-wrap.one div.val').text.strip() # 选中不带.one类的count-wrap容器 ongoing_projects = bcard.select_one('div.count-wrap:not(.one) div.val').text.strip() print(f"企业名称:{company_name}") print(f"总项目数:{total_projects}") print(f"进行中项目数:{ongoing_projects}")
完整可运行代码(含异常处理)
from bs4 import BeautifulSoup import requests main_url = "https://www.proptiger.com/bangalore/all-builders?page=1" response = requests.get(main_url) main_url_html = BeautifulSoup(response.text, "html.parser") for bcard in main_url_html.find_all('div', class_='b-card'): # 处理企业名称,增加异常判断避免页面结构变化导致报错 builder_wrap = bcard.find('div', class_='builder-details-wrap') company_name = builder_wrap.a.text.strip() if builder_wrap else "未知企业" # 处理项目数,增加异常判断 val_elements = bcard.find_all('div', class_='val') total_projects = val_elements[0].text.strip() if len(val_elements) >= 1 else "0" ongoing_projects = val_elements[1].text.strip() if len(val_elements) >= 2 else "0" print(f"---\n企业名称:{company_name}") print(f"总项目数:{total_projects}") print(f"进行中项目数:{ongoing_projects}")
内容的提问来源于stack exchange,提问作者HannibalTheCannibal
相关产品推荐
相关产品推荐

