Python Selenium爬取SVG房价图表 如何获取完整12个月价格数据
问题背景
- 采集目标:房源页面「Price Index(价格指数)」板块的SVG折线图,提取完整12个月的房屋历史月度价格数据
- 现有逻辑:通过XPath定位X轴渲染的月份span标签,模拟鼠标悬停读取提示框的价格、月份文本
- 现存问题:Chartist图表默认对X轴标签做隔月抽样显示,仅能定位到7个标签元素,只能拿到7个月的数据,缺失5个月的价格记录
现有实现代码
elements = driver.find_elements(by=By.XPATH, value="//*[local-name() = 'svg' and @class='ct-chart-line']//*[name() = 'g' and @class='ct-labels']//span[contains(@class,'ct-horizontal')]") print("WebElements: ", len(elements)) actions = ActionChains(driver) for el in elements: actions.move_to_element(el).perform() time.sleep(1) print(driver.find_element(by=By.CSS_SELECTOR, value="div.chartist-tooltip").text) print(driver.find_element(by=By.CSS_SELECTOR, value="div.ct-axis-tooltip-x").text)
现有运行输出
WebElements: 7 32,388,054 ==> Jun 2021 33,828,816 ==> Aug 2021 36,064,647 ==> Oct 2021 38,336,196 ==> Dec 2021 39,535,707 ==> Feb 2022 40,257,851 ==> Apr 2022 40,733,506 ==> May 2022
问题原因
原有定位逻辑选择的是X轴的可视化标签元素,Chartist为了避免标签重叠,会自动抽稀X轴标签(隔2个月显示1个),但所有12个月份对应的数据点都已经渲染在折线的序列分组里,只是对应的X轴标签没有被显示出来,所以靠找标签的方式拿不全数据。
修复方案
直接定位折线图上所有实际数据点元素,替代原有找X轴标签的逻辑:
Chartist渲染的每个数据点都存放在g.ct-series分组下,类名为ct-point,不管X轴标签有没有显示,这些点都会存在,总数正好是12个。
修正后的代码如下:
from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains import time # 定位折线上所有实际数据点,替换原来找X轴标签的XPath elements = driver.find_elements( by=By.XPATH, value="//*[local-name()='svg' and @class='ct-chart-line']//*[name()='g' and contains(@class,'ct-series')]//*[name()='line' and contains(@class,'ct-point')]" ) print(f"找到数据点总数:{len(elements)}") # 正常输出应为12 actions = ActionChains(driver) result = [] for point in elements: actions.move_to_element(point).perform() time.sleep(0.5) # 等待提示框渲染即可,无需等待1秒 price = driver.find_element(By.CSS_SELECTOR, "div.chartist-tooltip").text month = driver.find_element(By.CSS_SELECTOR, "div.ct-axis-tooltip-x").text result.append(f"{price} ==> {month}") # 遍历输出全量数据 for item in result: print(item)
兜底方案(部分点定位失败时使用)
如果个别页面的ct-point元素被样式隐藏无法定位,可以直接获取图表绘图区域的坐标范围,按12个月份等距分布的规则,计算每个月对应的鼠标悬停位置:
# 获取SVG图表的位置和尺寸 chart = driver.find_element(By.CSS_SELECTOR, "svg.ct-chart-line") chart_rect = chart.rect # 扣除Chartist默认绘图区边距,可根据实际页面微调 left_pad = 40 right_pad = 20 start_x = chart_rect['x'] + left_pad end_x = chart_rect['x'] + chart_rect['width'] - right_pad step = (end_x - start_x) / 11 # 12个点对应11个间隔 actions = ActionChains(driver) for i in range(12): hover_x = start_x + step * i # 偏移量相对于元素左上角计算,y轴取绘图区垂直居中位置 actions.move_to_element_with_offset(chart, hover_x - chart_rect['x'], chart_rect['height']/2).perform() time.sleep(0.5) price = driver.find_element(By.CSS_SELECTOR, "div.chartist-tooltip").text month = driver.find_element(By.CSS_SELECTOR, "div.ct-axis-tooltip-x").text print(f"{price} ==> {month}")
内容的提问来源于stack exchange,提问作者Asif Mehmood
相关产品推荐
相关产品推荐

