十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

全国水质数据采集与清洗标准化实战:从爬虫到分析

全国水质数据采集与清洗标准化实战:从爬虫到分析 简介这份全国各流域水质数据集基于环保部门公开数据整理每日更新面向环保研究人员、数据科学家及水环境治理相关从业者。压缩包共309个文件含308个JSON数据文件及1个Markdown说明文档整体仅2.68MBJSON按日期存储日度水质监测结果MD文件用于说明字段结构及使用方式。数据涵盖主要河流、湖泊、水库的pH值、溶解氧、氨氮、化学需氧量、总磷、总氮等多项指标可支撑污染源解析、趋势追踪与治理效果评估。已有2599人学习下载配合清晰的文件命名与目录结构方便按时间序列批量处理也可结合接口变更记录进行版本适配是开展中国水环境质量研究与政策制定的实用基础数据。 很多年前我第一次接触水质数据时想的特别简单找个网站把全国各流域的水质数据爬下来画几张图完事。结果真正动手才发现这摊水比想象中深得多——数据源分散、格式混乱、字段命名不统一有些站点还带反爬好不容易把数据弄下来单位又是五花八门pH、溶解氧、高锰酸盐指数、氨氮、总磷……光是清洗就得折腾掉半条命。这个项目名就叫water_quality目标很直接把全国各流域的水质数据整合成一套统一、干净、可复用的数据集。目前这套流程我已经跑通了完整链路——自动抓取、字段归一化、指数换算、按《地表水环境质量标准》自动定类最终落库成一张可以直接查的表。这篇文章就完整拆一遍我的技术方案和踩坑实录给同样被水质数据折磨过的人一个参考。1. 需求拆解与整体思路1.1 水质数据的核心痛点先说个结论水质数据不算稀缺稀缺的是“干净”的水质数据。我最初的目标很简单——拿到全国主要流域监测断面的水质指标做趋势分析和地域对比。真正搜了一圈之后发现问题集中在三点第一数据源极度分散。既有国家的公开平台也有各省市的独立发布渠道还有论文附录里零散的监测记录。每个地方的发布格式还不一样有的给 Excel有的给 HTML 表格有的干脆是 PDF。第二字段标准不统一。同样是监测断面A 平台叫“高锰酸盐指数”B 平台叫“CODMn”C 平台可能连单位都给你标成 mg/L另一个平台却用 μg/L。同一份数据不做单位归一化根本没法横向比。第三质量参差不齐。缺测值、异常值、重复记录、时间断档……如果把原始数据直接拿来用分析结果基本没法看。这个项目的核心思路就是把上面这些脏活累活一次性搞定——用一套自动化流程把多源数据统一清洗成标准结构保证任何人拿到手就能直接分析不需要再花三天做数据预处理。1.2 技术选型为什么这么做工具选型我遵循一条原则够用、好维护、样例多。抓取层用 Python requests BeautifulSoup遇到需要执行 JS 的动态页面就上 Selenium覆盖面足够广。数据处理层用 pandas这个没什么悬念表格数据清洗的事实标准。存储层用 SQLite单文件落库免部署分享起来拷个文件就行。可视化先用 matplotlib pyecharts 做探索性分析后面再按需接 BI 工具。这一套组合没有特别花哨的组件但在数据采集这个场景下非常稳定。我试过用 Scrapy 做分布式抓取对单个数据源来说完全是杀鸡用牛刀。Scrapy 适合大规模爬虫工程而水质数据这种中小体量、多源异构的场景requests BeautifulSoup 反而更灵活排查问题也更直接。提示如果你的目标是做长期巡检或者数据量真的很大比如每分钟级的水质自动站数据再上 Scrapy 不迟。日常的分析型项目别把架构搞复杂了。2. 数据采集方案与落地细节2.1 数据源怎么选、怎么判断可靠性数据源的选择直接决定数据质量的上限。我的筛选标准有三个有明确的监测依据、公开可访问、持续更新。我优先选择国家地表水水质自动监测实时数据发布系统这类官方公开渠道数据权威性有保障字段相对完整站点覆盖全国主要流域。省市级的环保部门公开数据作为补充尤其是国家平台覆盖不到的小流域和湖泊。还有一个容易被忽略的渠道——论文附录。很多环境科学领域的论文会在附录里放出详细的监测数据尤其是一些中小河流的数据平时根本找不到官方发布渠道但论文里可能有连续几年的完整记录。用正则表达式或者 Tabula 这种 PDF 解析工具就能把这些数据提取出来。筛选数据源时保留一个“来源 ID”字段这样任何一条记录都能回溯到原始出处方便后续核验。这个习惯值得养成尤其当数据要用于论文或报告时溯源能力就是数据的生命线。2.2 抓取策略请求频率、解析与断点续传抓取层的设计要温柔且稳妥。几个关键细节请求频率控制统一走一个带随机延迟的请求函数延迟区间设置在 1~3 秒相邻请求之间不完全固定模拟真人浏览的节奏。抓取频率别太激进这不是跟谁比赛数据源被封了才是最麻烦的。解析容错每个字段的解析都包在 try/except 里单个字段解析失败不影响整条记录入库。宁可字段留空也不能因为一行脏数据中断整个流程。断点续传抓取进度记录在一个本地 JSON 文件里记录每个页面已经抓取到的页码。中断后重新运行脚本直接从断点继续不用从头开始。import requests import time import json from bs4 import BeautifulSoup def safe_get(url, session, retries3): for attempt in range(retries): try: time.sleep(random.uniform(1, 3)) resp session.get(url, timeout15) if resp.status_code 200: return resp except requests.RequestException as e: print(f[Retry {attempt1}] {url} - {e}) return None def get_resume_point(resume_file): try: with open(resume_file, r, encodingutf-8) as f: return json.load(f).get(page, 1) except FileNotFoundError: return 1注意代码层面做好编码统一数据源的页面编码可能是 utf-8 也可能是 gbk解析之前先用 resp.apparent_encoding 做一次判断。这个细节坑了我两次后来固定成工具函数才消停。2.3 动态加载页面的处理思路部分数据平台的表格是后加载的请求静态 HTML 拿不到任何数据。这种情况无非两条路一是找后端接口地址直接请求 JSON二是上浏览器渲染工具。我的首选方案是前者——打开浏览器开发者工具切到 Network 面板翻页操作时盯住 XHR 请求找到真正返回数据的那个接口。这些接口往往不需要过于复杂的签名参数直接 requests 请求就能拿到结构化 JSON省掉了 Selenium 的启动开销。只有当数据接口本身加密参数太复杂、短时间破解代价太高时才启用 Selenium 兜底。但 Selenium 每次启动浏览器很耗时而且占用资源较大不适合大规模抓取只作为最后的手段。3. 数据清洗与标准化实战3.1 序号换站名、别名规整拿到原始数据后的第一件事是字段对齐。原始数据的表头可能叫“序号”“站点名称”“pH”这样的中文名也有的表头直接用英文缩写——“Station”“DO”“CODMn”。我设计了一套字段映射方案把原始字段统一映射到内部标准字段。field_mapping { 序号: id, 站点名称: station_name, pH: ph, 溶解氧: do, 高锰酸盐指数: codmn, CODMn: codmn, 氨氮: nh3n, 总磷: tp, 总氮: tn, }站名和指标名的别名问题比想象中严重。同一指标可能有五六种写法同一站点在不同年份的记录里可能换了名字。这种时候不能靠正则硬扛直接维护一张映射表遇到未知名称就停下来人工确认一次确认过的名字就固定进映射表下次自动处理。数据清洗的前两天基本都在干这个活。3.2 单位归一化与浓度换算这是最容易被忽视的环节。像总磷、总氮这类指标不同数据源有用 mg/L 的也有用 μg/L 的差着三个数量级。如果不做单位归一化画图的时候会莫名出现几个“异常高值”查半天发现是单位没换算。我在内部统一采用 mg/L 作为基准单位因为国标的限值就是以 mg/L 为单位的换算逻辑集中在一个函数里def normalize_units(value, unit_from, indicator): # 统一转为 mg/L if unit_from μg/L: return value / 1000.0 if unit_from mg/L: return value # 其他特殊单位按指标处理 return value换算后的数据再根据《地表水环境质量标准》GB 3838-2002的限值表自动给每条记录打上水质类别标签——I 类到劣 V 类对应从“优”到“重度污染”。有了这个分级字段后续分析直接按类别聚合就行省去了频繁查标准表的功夫。3.3 缺失值处理策略水质数据的缺失值处理不能一刀切。我总结了一套分层策略缺测值数据源明确标注“-”或“缺测”→ 置为 NaN不填数。这是最诚实的选择水质数据本身是周期性波动很明显的指标擅自用均值填充会抹掉真实变化特征。单次异常跳变比如 pH 12.5→ 先判定为离群值结合前后两次记录判断是否属于设备故障确认异常后置为 NaN。连续缺失超过 30% 的断面 → 该断面的时间序列分析价值已经很低分析时直接剔除但保留在原始表中备查。经验宁可保留缺失也不要硬造数据。很多下游分析任务对“假数据”的容忍度比“缺数据”低得多。4. 数据分析与可视化实践4.1 流域断面水质类别分布清洗完成后的第一张图我建议先画水质类别分布。把所有断面按 I~劣 V 类的数量做一个堆叠柱状图一眼就能看出整体分布形态。这类图既能验证数据清洗效果如果劣 V 类占了大半要么数据源有偏要么清洗哪里出了问题也能给后续分析定个基调——到底重点分析“优水区的变化趋势”还是“污染区的治理效果”。4.2 时间序列趋势与季节性识别水质的季节规律非常明显。以氨氮为例枯水期河流稀释能力下降氨氮浓度往往走高丰水期则相反。把断面数据按月聚合画时间序列折线能清楚看到每年的振荡周期。有一个细节值得注意降水稀释与面源冲刷是双重效应比如暴雨过后的一两天部分污染物浓度可能不降反升——这是地表径流把岸上污染物冲进河流的结果。所以分析水质趋势时不能只看月均值要结合降雨事件做事件维度的解析否则会得出“下雨导致水质变差”这种片面的结论。我在实践中建议至少做两个时间粒度的分析年度趋势看治理效果月度/事件粒度看异常波动。两张图配合使用才能讲清楚一个流域的水质故事。4.3 空间分布与热力展示空间维度的展示比时间维度更适合做汇报——一张流域水质热力图比十张折线图都有说服力。我选的是 pyecharts 地图底图的方案把经纬度信息和综合水质类别映射成地图上的点/面颜色。需要注意的坑坐标系的统一。不同数据源的经纬度有的用 GCJ-02国测局坐标有的用 WGS-84混用会导致点位偏移几公里甚至更远。统一转成 WGS-84 后再做地图标注才能跟底图对上。绘图方案上热力图适合区间对比散点地图适合精确点位展示。如果看流域级别的整体水质建议用分级设色地图如果关注具体断面的监测值用带 tooltip 的散点地图更直观。5. 常见问题与排查技巧实录5.1 高频问题速查表问题现象可能原因排查方法请求返回 403触发服务端反爬策略加 User-Agent / Referer 伪装降低请求频率解析结果全为空页面数据为动态加载打开开发者工具查找真实 XHR 接口中文乱码页面编码判断错误用resp.apparent_encoding覆盖resp.encoding数据出现数量级异常单位未归一化检查原始单位是 μg/L 还是 mg/L统一换算站点名对不上站点改名或重名维护断面别名映射表按经纬度辅助匹配时间字段解析失败日期格式不统一用pd.to_datetime(..., errorscoerce)统一解析5.2 反爬应对的边界意识做数据采集要守住两条底线一是请求频率控制好别把对方服务器打得喘不过气二是数据仅用于个人学习研究不做商业化转售。我宁可慢一点比如每分钟只请求 60 次以内也要保证不给数据源添麻烦。被临时封了 IP 也没必要慌停半小时再跑通常就好了。真要长期抓取建议把抓取逻辑和数据存储走本地化——先持久化到 CSV 临时文件再分批入库避免长任务中途失败导致内存数据全部丢失。5.3 数据质量验证的“土办法”清洗完数据别急着画图。先写几条简单的校验逻辑过一遍断面总数是否在合理范围全国范围上千个断面是正常的个位数就要怀疑抓取遗漏。时间跨度是否完整是否有整年缺失。随机抽几个站点人工去原始平台核对数值是否一致。我每次跑完清洗流程都会抽 5 个站点人工核对用抽样代替全量验证既保证质量又控制时间成本。别嫌土这个环节救过我不少次。6. 项目扩展与实际使用建议数据清洗完成后只是拿到了一个数据库而已真正的生活场景价值还需要配合实际需求去挖掘。如果你有自己的水质监测设备比如鱼缸水质检测仪、小型河流环境监测浮标这套数据可以直接作为背景基准数据来用——把你的观测值和全国同类流域的分布做对比快速判断自己的数据是否在正常范围内。这也是我目前常态化的使用方式单独维护一张本地监测表与water_quality库里的同流域数据做 join 对比。如果想把项目做成长期巡检工具可以加上定时调度比如 cron 或 GitHub Actions 计划任务每天自动更新一次数据。配合 SQLite 存储天然支持增量插入的特性不用每次全量重抓。再往后可以引入机器学习模型做水质预测。有一个比较成熟的思路用上游断面的历史水质数据和当天的水文气象数据降雨量、流量等训练一个回归模型预测下游断面的氨氮或溶解氧浓度。这个方向的可行性很高因为水质数据本身的季节性规律很清晰特征工程做好之后模型精度会比想象中好。最后再分享一个我的个人习惯这个项目的代码和数据文件我用统一的目录结构归档raw/放原始抓取内容processed/放清洗后的标准表scripts/放各阶段的处理脚本。这样无论是三个月后回来自查还是同事需要复用数据都能快速定位不用再翻聊天记录和网盘找文件。水质数据这个领域的核心门槛从来不是技术而是耐心——多源数据、混乱字段、缺失记录每一道脏活都得一道道过。把标准化流程沉淀下来后面再做任何跟水环境相关的分析底气都会不一样。本文还有配套的精品资源点击获取
返回列表