如何用Python抓取IEA桑基图网页数据?(BS、Selenium尝试未果)
解决IEA桑基图数据抓取问题
问题根源
你用BeautifulSoup抓不到数据,核心原因是页面的桑基图数据不是静态嵌入HTML的——页面加载完成后才会通过JavaScript调用后端API拉取数据,requests.get只能拿到初始的空壳HTML,自然拿不到动态加载的内容。
方案1:直接调用API获取数据(推荐)
这个网站的桑基图数据是通过公开API返回的JSON格式,直接请求API比模拟浏览器高效得多,也更稳定。
操作步骤
- 打开浏览器F12开发者工具,切换到「Network」标签页,刷新页面;
- 筛选「XHR」类型请求,找到名称类似
balance?country=Indonesia的请求,复制其接口地址; - 用Python的
requests库直接请求该接口,解析返回的JSON数据。
示例代码
import requests # 对应Indonesia的Balance数据API接口 api_url = "https://www.iea.org/api/sankey/balance?country=Indonesia" # 模拟浏览器请求头,避免被拦截 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } response = requests.get(api_url, headers=headers) if response.status_code == 200: data = response.json() # 打印数据结构,按需提取字段 print("数据结构:") print(data.keys()) # 提取节点数据 print("\n节点信息:") for node in data['nodes']: print(f"ID: {node['id']}, 名称: {node['name']}, 数值: {node['value']}") # 提取链路数据(桑基图的流向关系) print("\n链路信息:") for link in data['links']: print(f"从 {link['source']} 到 {link['target']}, 流量: {link['value']}") else: print(f"请求失败,状态码:{response.status_code}")
方案2:用Selenium正确获取动态数据
如果一定要用Selenium,关键是要等页面完全加载,确保数据元素生成后再抓取。
示例代码
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC url = "https://www.iea.org/sankey/#?c=Indonesia&s=Balance" # 初始化Chrome浏览器(需提前下载对应版本的chromedriver) driver = webdriver.Chrome() driver.get(url) try: # 最多等待10秒,直到桑基图数据元素出现 wait = WebDriverWait(driver, 10) sankey_data = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "sankey-data"))) # 打印数据文本 print(sankey_data.text) # 更高效的方式:直接执行JS获取页面中的数据对象 raw_data = driver.execute_script("return window.sankeyData;") print("\n原始JSON数据:") print(raw_data) finally: # 关闭浏览器 driver.quit()
后续处理
拿到JSON数据后,你可以用pandas库把它转换成表格格式,比如:
import pandas as pd # 把节点数据转成DataFrame nodes_df = pd.DataFrame(data['nodes']) # 把链路数据转成DataFrame links_df = pd.DataFrame(data['links']) print("节点表格:") print(nodes_df) print("\n链路表格:") print(links_df)
内容的提问来源于stack exchange,提问作者Bagas
相关产品推荐
相关产品推荐

