
本文介绍如何使用python的requests和beautifulsoup库精准抓取挪威yr网站的雪深数据,并将其转换为带列名的pandas dataframe,重点解决class参数命名冲突、表格结构解析及数据类型处理等实战问题。
本文介绍如何使用python的requests和beautifulsoup库精准抓取挪威yr网站的雪深数据,并将其转换为带列名的pandas dataframe,重点解决class参数命名冲突、表格结构解析及数据类型处理等实战问题。
要从YR挪威雪深页面(如Jordalen - Nåsen区域)提取结构化雪深数据,关键在于正确识别HTML表格语义结构,而非仅定位单个元素——因为该页面实际以响应式表格(fluid-table)组织全部观测点数据,每个行(tr.fluid-table__row)对应一个地点,各列(th.fluid-table__cell--heading)包含地点名称、当前雪深、24h变化、48h变化及累计雪深等字段。
以下是完整、健壮的实现方案:
import pandas as pd
import requests
from bs4 import BeautifulSoup
# 1. 获取网页内容
url = "https://www.php.cn/link/37bc3d1076fca822d98e539754dae9cd"
response = requests.get(url)
response.raise_for_status() # 确保请求成功
# 2. 解析HTML
soup = BeautifulSoup(response.content, "html.parser")
# 3. 提取表头(注意:使用 class_ 而非 class,因 class 是Python保留字)
headers = [th.get_text(strip=True) for th in soup.find_all("th", class_="fluid-table__cell--heading")]
# 4. 提取所有数据行(跳过空行或无文本的tr)
rows = []
for tr in soup.find_all("tr", class_="fluid-table__row fluid-table__row--link"):
# 提取每行中所有非空文本子节点(排除图标、空白标签等干扰)
cells = [td.get_text(strip=True) for td in tr.find_all(["td", "th"]) if td.get_text(strip=True)]
if cells: # 仅保留含有效文本的行
rows.append(cells)
# 5. 构建DataFrame,并对数值列尝试类型转换
df = pd.DataFrame(rows, columns=headers)
# 将雪深相关列(如含"cm"的字段)清洗为整数:移除单位,转int
depth_cols = [col for col in df.columns if "cm" in col or "dybde" in col.lower()]
for col in depth_cols:
df[col] = df[col].str.replace(r'[^\d\-]', '', regex=True).replace('', '0').astype(int, errors='ignore')
print(df.head())
✅ 关键要点说明:
- class_= 是BeautifulSoup中指定CSS类的唯一正确写法,class="..."会引发语法错误;
- 直接使用 find_all("span", class_="snow-depth__value") 只能获取所有雪深值的扁平列表,丢失地点归属关系,无法满足结构化分析需求;
- 表格主体由
定义,配合 表头,构成标准二维结构,应优先按行解析; - 实际数据中常含单位(如"35 cm")、符号(如"–")或空格,需用正则清洗后再类型转换,避免 astype(int) 报错;
- 建议添加 response.raise_for_status() 和异常处理,提升脚本鲁棒性(生产环境必备)。
最终生成的DataFrame将包含完整的地点、实时雪深、短期变化及累计值,可直接用于后续分析、可视化或定时爬取监控。











