如何使用Selenium和Python抓取Highcharts图表数据
报错原因及解决方法
你提到的「检查元素时的日期格式和页面展示月份不一致」不是触发NoSuchElementException的直接原因,报错的核心诱因有以下几点:
- 绝对路径XPath稳定性差:SimilarWeb的DOM结构是动态生成的,不同站点、不同版本的页面模块排序、元素层级都会发生调整,你写的
/html/开头的绝对路径只要结构稍微变动就会定位失败。 - SVG元素定位逻辑问题:Highcharts图表的tooltip默认不会挂载到DOM中,只有鼠标hover到对应数据点时才会动态生成,你在没有触发hover的情况下直接查找tooltip元素自然不存在。
- 等待逻辑不足:固定的sleep时间无法适配不同网络环境下的页面渲染速度,很多时候图表还没完全加载完成,你就执行了元素查找操作,自然找不到目标元素。
你补充的代码返回空列表的原因是:find_elements_by_xpath返回的是元素列表,列表本身没有.text属性,同时你hover的是图表的path路径元素,而Highcharts的tooltip触发对象是数据点元素,hover到path上不会触发tooltip生成,自然拿不到对应内容。
修正后的核心参考代码如下:
# 保留你原有导入、浏览器初始化、站点列表的代码 for crawler in websites: browser.get(crawler) # 等待核心指标模块加载完成 WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".engagement-list"))) # 用CSS选择器做相对定位,稳定性远高于绝对XPath website_names = browser.find_element(By.CSS_SELECTOR, ".app-header__domain-name a").get_attribute("href") total_visits = browser.find_element(By.CSS_SELECTOR, ".engagement-list__item:nth-child(1) .engagement-list__item-value").text avg_visit_duration = browser.find_element(By.CSS_SELECTOR, ".engagement-list__item:nth-child(2) .engagement-list__item-value").text pages_per_visit = browser.find_element(By.CSS_SELECTOR, ".engagement-list__item:nth-child(3) .engagement-list__item-value").text bounce_rate = browser.find_element(By.CSS_SELECTOR, ".engagement-list__item:nth-child(4) .engagement-list__item-value").text # 等待图表渲染完成 WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, "svg.highcharts-root"))) # 定位图表的数据点元素,而非路径元素 points = browser.find_elements(By.CSS_SELECTOR, "svg.highcharts-root .highcharts-markers .highcharts-point") res = [] for point in points: # hover到数据点,触发tooltip生成 ActionChains(browser).move_to_element(point).pause(0.5).perform() # 等待tooltip可见后再提取内容 tooltip = WebDriverWait(browser, 5).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "g.highcharts-tooltip text"))) tspan_list = tooltip.find_elements(By.TAG_NAME, "tspan") if len(tspan_list) >=3: date = tspan_list[0].text visit_value = tspan_list[2].text res.append((date, visit_value)) print(f"日期:{date},访问量:{visit_value}") # 打印所有采集数据 print('站点地址:', website_names) print('总访问量:', total_visits) print('平均访问时长:', avg_visit_duration) print('单次访问页数:', pages_per_visit) print('跳出率:', bounce_rate) print('月度访问数据:', res)
内容的提问来源于stack exchange,提问作者technophile_3
相关产品推荐
相关产品推荐

