如何使用Python爬取网页交互式图表的底层数据
问题结论
数据存储位置
你在Chrome开发者工具Elements标签页找不到图表数据点是正常情况:
- 目标页面为VGChartz美国区硬件年度销量统计页,底部交互式图表基于Highcharts库渲染,所有数据点位最终是JS执行后动态生成的SVG图形,不会以静态文本/表格节点的形式直接写在初始HTML源码里,手动翻DOM树查找效率极低。
- 数据没有加密,存在两个可直接提取的位置:
- 页面初始响应的HTML内嵌的
<script>代码块中,直接写入了Highcharts初始化所需的全量配置,包含所有时间维度、各硬件型号的对应销量数值 - 页面加载过程中也会拉取对应结构化数据,通过Network面板筛选
Fetch/XHR类型请求就能看到对应的数据接口
- 页面初始响应的HTML内嵌的
Python提取方案
提供两种可直接运行的实现,优先选第一种轻量方案,不需要模拟浏览器,爬取速度快、资源占用低。
方案1:直接请求页面+正则提取内嵌JS数据(推荐)
不需要依赖浏览器自动化工具,仅用requests库请求页面后,从内嵌JS中匹配提取图表配置即可,示例代码:
import requests import re import json target_url = "https://www.vgchartz.com/tools/hw_date.php?reg=USA&ending=Yearly" # 替换成自己浏览器的UA即可,避免被默认请求头拦截 request_headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" } response = requests.get(target_url, headers=request_headers) response.encoding = response.apparent_encoding # 匹配页面中Highcharts初始化传入的配置对象 chart_config_match = re.search(r"Highcharts\.chart\('.*?',\s*(\{.*?\})\);", response.text, re.S) if not chart_config_match: raise ValueError("未匹配到图表配置,检查页面结构是否变更") chart_config_str = chart_config_match.group(1) # 提取X轴年份分类 years_raw = re.search(r"categories:\s*(\[.*?\])", chart_config_str, re.S).group(1) year_list = json.loads(years_raw) # 提取各硬件的名称和对应年度销量 sales_result = [] series_match_iter = re.finditer(r"name:\s*'(.*?)',\s*data:\s*(\[.*?\])", chart_config_str, re.S) for match in series_match_iter: hw_name = match.group(1) sales_raw = match.group(2) sales_list = json.loads(sales_raw) sales_result.append({ "hardware": hw_name, "sales_by_year": dict(zip(year_list, sales_list)) }) # 示例:打印所有含"PS5"的硬件销量数据 for item in sales_result: if "PS5" in item["hardware"]: print(f"{item['hardware']} 美国年度销量:", item["sales_by_year"])
如果遇到JS对象格式不规范导致json.loads报错,可以安装demjson3库做兼容解析,安装命令为pip install demjson3,替换对应解析逻辑为demjson3.decode(待解析字符串)即可。
方案2:浏览器自动化直接读取图表实例数据
如果后续页面结构调整,内嵌JS的匹配规则失效,可以用Selenium等浏览器自动化工具,直接调用Highcharts实例的内置方法读取数据,完全不需要解析DOM或源码,示例代码:
from selenium import webdriver from selenium.webdriver.chrome.options import Options import json chrome_options = Options() chrome_options.add_argument("--headless=new") # 无头模式,不弹出浏览器窗口 driver = webdriver.Chrome(options=chrome_options) driver.get("https://www.vgchartz.com/tools/hw_date.php?reg=USA&ending=Yearly") # 执行JS直接获取图表结构化数据 extract_js = """ const targetChart = Highcharts.charts.at(-1); return { years: targetChart.xAxis[0].categories, hardware_series: targetChart.series.map(series => ({ name: series.name, sales: series.data.map(point => point.y) })) } """ chart_data = driver.execute_script(extract_js) driver.quit() # 后续按需处理结构化数据即可 print(json.dumps(chart_data, indent=2, ensure_ascii=False))
注意事项
- 爬取时请控制请求频率,不要对站点正常运行造成压力
- 两种方案拿到的数据都是站点公开的展示数据,不涉及破解加密或权限绕过
内容的提问来源于stack exchange,提问作者Ng.Alina
相关产品推荐
相关产品推荐

