
在进行网页数据抓取时,我们经常会遇到数据以动态方式呈现的情况,例如图表中的详细信息通常在鼠标悬停时才显示。对于这类场景,许多开发者会首先考虑使用selenium等浏览器自动化工具来模拟用户行为。然而,并非所有动态内容都需要完整的浏览器模拟,有时通过更直接的方式可以显著提高效率和稳定性。
原始问题中尝试使用Selenium来模拟鼠标悬停以获取图表数据。其核心思路是定位图表元素,然后对每个潜在的数据点执行鼠标悬停操作,期望通过ActionChains触发悬停信息并抓取。
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("start-maximized")
webdriver_service = Service()
driver = webdriver.Chrome(options=options, service=webdriver_service)
driver.get('https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i9-11900K+%40+3.50GHz&id=3904')
# 尝试定位图表元素
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//*[@id='placeholder']/div/canvas[2]")))
# 错误点:element是一个WebElement对象,不可迭代
for el in element:
ActionChains(driver).move_to_element(el).perform()
mouseover = WebDriverWait(driver, 30).until(EC.visibility_of_element_located((By.SELECTOR, ".placeholder > div > div.canvasjs-chart-tooltip > div > span")))
print(mouseover.text)上述代码存在两个主要问题:
在许多情况下,图表所展示的数据并非完全通过前端AJAX请求动态获取,而是直接嵌入在页面的JavaScript代码中。这意味着,我们无需模拟浏览器行为,可以直接从网页源代码中提取这些数据。
对于CPU价格历史图表这类数据,通过检查网页源代码可以发现,其数据通常以JavaScript变量的形式直接存在于HTML中。例如,常见的图表库(如CanvasJS、Highcharts等)在初始化时会直接在<script>标签中定义数据数组。
立即学习“Python免费学习笔记(深入)”;
我们可以利用Python的requests库获取完整的HTML内容,然后使用正则表达式(re模块)从JavaScript代码中匹配并提取所需的数据。最后,结合pandas库对提取的结构化数据进行进一步处理,如类型转换、时间格式化等。
使用requests.get()方法获取指定URL的HTML内容。
import requests import re import pandas as pd url = "https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i9-11900K+%40+3.50GHz&id=3904" html_text = requests.get(url).text
通过分析目标网页的源代码,我们可以找到图表数据通常以dataArray.push({x: ..., y: ...})的形式存在于某个JavaScript块中。我们可以构建一个正则表达式来匹配这些模式。
例如,目标数据格式为{x: 时间戳, y: 价格}。正则表达式r"dataArray\.push\({x: (\d+), y: ([\d.]+)}"可以精确匹配:
# 使用re.findall找到所有匹配的数据对
# re.findall会返回一个元组列表,每个元组包含正则表达式捕获的组
data_tuples = re.findall(r"dataArray\.push\({x: (\d+), y: ([\d.]+)}", html_text)将提取到的数据转换为Pandas DataFrame,便于后续的数据清洗、分析和存储。 时间戳通常是Unix时间戳(秒或毫秒),需要转换为可读的日期时间格式。
# 创建DataFrame,指定列名 df = pd.DataFrame(data_tuples, columns=["time", "price"]) # 将'time'列从字符串转换为整数,再除以1000(如果原始是毫秒),然后转换为datetime对象 # 示例中原始时间戳是秒,所以直接除以1000得到秒,然后unit='s' df["time"] = pd.to_datetime(df["time"].astype(int) // 1000, unit="s") # 将'price'列转换为浮点数 df["price"] = df["price"].astype(float) print(df.tail())
import requests
import re
import pandas as pd
def scrape_cpu_pricing_history(cpu_url: str) -> pd.DataFrame:
"""
从CPU Benchmark网站抓取指定CPU的价格历史数据。
数据通过解析网页内嵌的JavaScript变量获取。
Args:
cpu_url (str): CPU详细页面的URL。
Returns:
pd.DataFrame: 包含时间戳和价格的DataFrame。
如果抓取失败或未找到数据,返回空的DataFrame。
"""
try:
html_text = requests.get(cpu_url, timeout=10).text
except requests.exceptions.RequestException as e:
print(f"请求URL失败: {e}")
return pd.DataFrame()
# 正则表达式匹配JavaScript中的dataArray.push({x: time, y: price})模式
# x是时间戳(秒),y是价格
pattern = r"dataArray\.push\({x: (\d+), y: ([\d.]+)}"
data_matches = re.findall(pattern, html_text)
if not data_matches:
print("未在页面中找到价格历史数据。")
return pd.DataFrame()
# 将匹配结果转换为DataFrame
df = pd.DataFrame(data_matches, columns=["time", "price"])
# 数据类型转换和格式化
try:
# 原始时间戳通常是毫秒级,转换为秒后再转datetime
# 根据观察,此网站的时间戳是秒级,所以直接//1000是错误的,应根据实际情况调整
# 此处根据答案中的 // 1000 判断,原始数据可能以毫秒存储,但to_datetime的unit='s'表示输入是秒
# 如果原始数据是秒,则无需 // 1000
df["time"] = pd.to_datetime(df["time"].astype(int), unit="s") # 假设原始是秒
df["price"] = df["price"].astype(float)
except ValueError as e:
print(f"数据类型转换失败: {e}")
return pd.DataFrame()
return df
# 示例调用
cpu_detail_url = "https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i9-11900K+%40+3.50GHz&id=3904"
pricing_df = scrape_cpu_pricing_history(cpu_detail_url)
if not pricing_df.empty:
print("成功获取CPU价格历史数据:")
print(pricing_df.tail())
else:
print("未能获取CPU价格历史数据。")输出示例:
time price 236 2023-05-28 06:00:00 317.86 237 2023-05-29 06:00:00 319.43 238 2023-05-30 06:00:00 429.99 239 2023-05-31 06:00:00 314.64 240 2023-06-01 06:00:00 318.9
通过上述方法,我们能够以更高效、更稳定的方式从网页中提取图表数据,避免了不必要的浏览器自动化开销,使爬虫程序更加健壮。在遇到类似问题时,优先分析数据源,选择最直接的抓取策略是提升爬虫性能的关键。
以上就是Python网络爬虫:高效提取网页图表悬停数据的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号