如何使用html.parser获取div标签内的目标价格信息?
解决HTML中获取span标签后文本价格的问题
你是不是头疼怎么拿到<div class='card-product__price'>里,那个旧价格span后面的目标价格?现在你的HTMLParser代码输出空值,咱们先找找问题出在哪,再给你搞定它。
先说说你现有代码的问题
- 目标div的class匹配错了:你代码里判断的是
card-product__details,但实际要找的div class是card-product__price,这第一步就没命中目标! - 没有跟踪span标签的状态:目标价格是span的兄弟文本节点,你的代码没标记“已经过了旧价格span”这个状态,自然不知道什么时候该抓取后续的文本。
- 触发条件逻辑有问题:
self.is_price_field的触发条件不明确,导致handle_data里的判断一直不成立,根本不会去处理数据。
方案一:修正原生HTMLParser代码
如果一定要用HTMLParser,咱们调整逻辑,跟踪进入目标div、经过span的状态,再抓取文本:
from html.parser import HTMLParser import re class PriceParser(HTMLParser): def __init__(self): super().__init__() self.in_target_div = False # 是否进入了目标价格div self.span_passed = False # 是否已经跳过了旧价格span self.target_price = None # 存储最终价格 def handle_starttag(self, tag, attrs): # 检查是否进入目标div if tag == 'div': attrs_dict = dict(attrs) if attrs_dict.get('class') == 'card-product__price': self.in_target_div = True # 如果在目标div里,检查是否是旧价格span elif self.in_target_div and tag == 'span': attrs_dict = dict(attrs) if attrs_dict.get('class') == 'card-product__price-old': self.span_passed = True # 标记已经遇到这个span def handle_endtag(self, tag): # 离开目标div时重置状态 if tag == 'div' and self.in_target_div: self.in_target_div = False self.span_passed = False def handle_data(self, data): # 只有满足三个条件才处理:在目标div、已过span、还没拿到价格 if self.in_target_div and self.span_passed and self.target_price is None: cleaned_text = data.strip() if cleaned_text: # 过滤掉纯空白的文本(比如换行、空格) # 清理掉非数字和小数点的字符,保留价格数值 self.target_price = re.sub('[^\d.]', '', cleaned_text) # 测试使用 html = ''' <div class='card-product__price'> <span class='card-product__price-old'>Old price is here</span> '199.99' </div> ''' parser = PriceParser() parser.feed(html) print(parser.target_price) # 输出: 199.99
方案二:用BeautifulSoup更省心
原生HTMLParser写起来太繁琐了,推荐用BeautifulSoup,几行代码就能搞定:
from bs4 import BeautifulSoup import re html = ''' <div class='card-product__price'> <span class='card-product__price-old'>Old price is here</span> '199.99' </div> ''' soup = BeautifulSoup(html, 'html.parser') # 找到目标div和里面的旧价格span price_div = soup.find('div', class_='card-product__price') old_price_span = price_div.find('span', class_='card-product__price-old') # 获取span的下一个兄弟文本节点,清理空白和无关字符 target_text = old_price_span.next_sibling.strip() cleaned_price = re.sub('[^\d.]', '', target_text) print(cleaned_price) # 输出: 199.99
这个方法里,next_sibling直接定位到span后面的文本节点,省去了复杂的状态跟踪,代码简洁太多。
内容的提问来源于stack exchange,提问作者Beginner
相关产品推荐
相关产品推荐

