电力能源公开数据采集实操:用 OpenClaw 合规抓取电网电价与发电量数据,生成区域能源供需分析报告

**摘要:**本文面向能源数据分析师、电力行业从业者和数据工程初学者,系统梳理电力能源公开数据的获取路径,并以 OpenClaw 数据采集框架为核心,完整演示如何合规抓取电网分时电价、月度发电量、装机容量与用电负荷等公开数据,再经过清洗、标准化和指标计算,最终生成一份可复用的区域能源供需分析报告。全文涵盖数据源盘点、合规边界、采集架构、核心代码、分析模型与报告输出等环节,并提供可直接运行的 Python 示例代码。

一、为什么用公开数据做区域能源供需分析

电力系统是经济社会运行的基础支撑,电价水平和发电结构直接影响工业生产成本、居民生活负担以及区域招商引资的竞争力。对于企业能源采购部门、售电公司、园区管理方和研究机构而言,及时掌握某一区域内电价的波动趋势、发电量的结构变化以及供需松紧程度,是制定购电策略、评估用能成本和判断投资机会的重要前提。

过去,这类数据往往分散在电网企业、电力交易中心、能源主管部门和统计机构的不同栏目中,获取门槛较高,更新节奏不一。近年来,随着电力市场化改革持续推进和政务数据开放水平提升,大量与电力能源相关的数据已经以公开网页、定期报表、API 接口或文件下载的形式对外提供。这为研究人员使用程序化手段批量采集、整合和分析数据创造了条件。

与商业数据终端相比,公开数据具有成本低、来源可追溯、口径相对透明等优势。但公开数据也存在结构不统一、字段命名混乱、历史版本缺失、部分页面需要动态渲染等现实问题。因此,一个稳定、可维护、可复用的数据采集流程就变得非常重要。本文将围绕这一目标,介绍如何使用 OpenClaw 框架搭建一套从采集、清洗到分析报告的完整链路。

需要特别强调的是,任何数据采集行为都应当遵守来源网站的访问规则、服务条款以及相关法律法规。本文所讨论的全部数据均为公开可查的统计信息,采集方式以低频、少量、非侵入式为主,不涉及绕过登录、破解验证码、暴力请求等不当手段。合规是开展能源数据工作的底线,也是本文所有技术方案的前提。

二、电力能源公开数据源全景梳理

要把区域能源供需分析做扎实,第一步不是急着写代码,而是先把数据源摸清楚。电力能源数据大致可以分成供给侧、需求侧、价格侧和宏观统计四个维度,每一类数据都有对应的权威公开渠道。

2.1 供给侧数据:发电量与装机容量

供给侧数据主要反映某一区域有多少电、用什么方式发出来的。核心指标包括全口径发电量、分类别发电量、发电设备利用小时数、新增装机容量和累计装机容量。这些数据的权威来源包括:

  • 国家能源局:按月发布全国电力工业统计数据,包含各省级行政区的发电量、装机容量等指标,部分数据以 PDF 或 Excel 形式提供。
  • 中国电力企业联合会:发布全国电力供需形势分析预测报告、月度电力统计快报,涵盖火电、水电、风电、太阳能发电和核电的详细数据。
  • 各省发展和改革委员会、能源局:发布本省电力运行情况,通常包含更细粒度的地市或行业数据。
  • 电网企业公开信息:国家电网和南方电网会定期发布经营区域内的电力运行情况,部分省份还会公布新能源消纳情况。

2.2 需求侧数据:用电量与最高负荷

需求侧数据反映区域的电力消费规模和时间分布。核心指标包括全社会用电量、分产业用电量、居民生活用电量、电网最高负荷、负荷率和最大峰谷差。这些数据主要来自:

  • 国家能源局:按月发布全社会用电量数据,并按产业和居民生活进行分类。
  • 省市级电力公司:在迎峰度夏、度冬等关键时期公布最高负荷数据。
  • 统计部门:在国民经济和社会发展统计公报、能源统计年鉴中提供年度用电数据。
  • 电力交易中心:发布电力中长期交易和现货市场的成交电量、成交价格,是判断供需松紧的重要市场信号。

2.3 价格侧数据:电价与交易价格

电价是最受关注的数据之一。在电力市场化改革背景下,电价已经形成「计划与市场并存」的复杂体系:

  • 目录销售电价:已经陆续退出历史舞台,但在部分省份的官方文件中仍可查询到历史基准。
  • 燃煤发电基准价:各省发改委公布,是理解区域内电源上网电价的重要参考。
  • 分时电价与峰谷电价:各省发布分时电价政策,明确尖峰、高峰、平段、低谷时段的划分及相应价格水平,部分省份还推出深谷电价。
  • 电力市场化交易价格:由各省电力交易中心按月、按季度公布,包括中长期交易均价、现货市场日前和实时电价等。
  • 电网代理购电价格:电网企业按月发布代理购电价格表,对工商业用户有直接参考价值。

2.4 宏观与交叉数据

除了直接的电力指标,区域能源供需分析往往还需要引入宏观变量,例如工业增加值、气温变化、主要行业产品产量等,用以解释用电量波动的原因。这些数据可以从国家统计局、地方统计部门以及中国气象局公开的气象数据中获取。

下面用一张表对主要数据源进行汇总,方便后续设计采集方案时快速对照。

数据类别 核心指标 主要公开来源 常见格式
发电量 全口径发电量、分类别发电量 国家能源局、中电联、省能源局 Excel、PDF、网页表格
装机容量 火电、水电、风电、光伏、核电装机 国家能源局、中电联 Excel、PDF
用电量 全社会用电量、分产业用电量 国家能源局、省电力公司 网页表格、新闻稿
最高负荷 电网最高负荷、峰谷差 省电力公司、发改委 新闻稿、通知
价格 基准价、分时电价、交易均价、现货电价 省发改委、电力交易中心、电网企业 通知文件、网页表格、API
宏观变量 工业增加值、气温、行业产量 统计局、气象局 Excel、API

在开始采集之前,建议先把目标区域对应的数据源逐一访问一遍,记录下每个来源的更新频率、字段口径和文件格式。这一步看似繁琐,却决定了后续清洗和建模的复杂度。数据源盘点做得越扎实,后面的自动化和报告生成就越顺畅。

三、OpenClaw 环境准备与项目初始化

OpenClaw 是一个面向开放数据采集与处理场景的轻量级数据工程框架,它以 Python 包的形式提供,核心能力包括:声明式采集任务定义、统一的数据抓取接口、内置的清洗与转换工具、任务调度支持,以及对接常见存储后端的能力。对于电力能源公开数据采集中常见的「网页表格、JSON 接口、Excel 文件」三类来源,OpenClaw 都提供了对应的处理器,可以在一个项目里统一管理。

3.1 安装与依赖

建议使用 Python 3.10 及以上版本,并在独立的虚拟环境中安装。打开终端,执行以下命令:

bash 复制代码
python -m venv energy_env
source energy_env/bin/activate
pip install openclaw pandas requests sqlalchemy openpyxl lxml schedule

这里除了 OpenClaw 本身,还安装了 pandas 用于数据清洗和指标计算,requests 用于基础 HTTP 请求,sqlalchemy 用于把采集结果写入数据库,openpyxl 用于读取和导出 Excel 文件,lxml 提供高性能的 HTML 解析能力,schedule 用于后续的定时任务。

安装完成后,可以先验证环境是否正常:

python 复制代码
import openclaw
import pandas as pd

print("OpenClaw version:", openclaw.__version__)
print("Pandas version:", pd.__version__)

如果控制台正常输出两个版本号,说明环境已经就绪。

3.2 初始化采集项目

OpenClaw 提供了项目脚手架命令,可以快速生成标准目录结构。在终端中执行:

bash 复制代码
openclaw init energy-report
cd energy-report

生成的项目目录结构大致如下:

text 复制代码
energy-report/
├── config.yaml
├── collectors/
│   ├── __init__.py
│   ├── price_collector.py
│   ├── generation_collector.py
│   └── demand_collector.py
├── processors/
│   ├── __init__.py
│   ├── cleaner.py
│   └── analyzer.py
├── storage/
│   └── energy.db
├── reports/
│   └── templates/
└── main.py

其中 config.yaml 是全局配置文件,collectors 目录存放各类采集器,processors 目录负责清洗和分析,storage 目录用于存放采集结果,reports 目录用于输出分析报告。这个结构可以随着项目推进不断扩展,但保持「采集、处理、分析、输出」四个环节分离,是长期维护的关键。

3.3 配置文件说明

在 config.yaml 中,可以集中管理数据源地址、请求头、限速策略和存储配置。一个基础配置示例:

yaml 复制代码
project:
  name: energy-report
  region: east-china

http:
  timeout: 30
  retry: 3
  min_interval: 5
  headers:
    User-Agent: "Mozilla/5.0 (X11; Linux x86_64) EnergyDataCollector/1.0"

storage:
  type: sqlite
  path: storage/energy.db

schedule:
  hourly: "0 9 * * *"
  monthly: "0 9 3 * *"

这里的 min_interval 设置为 5 秒,表示同一个数据源相邻两次请求之间至少间隔 5 秒。这个限速策略非常重要,既是对数据源服务器的尊重,也是避免被识别为异常流量的自我保护措施。在实际生产环境中,建议把限速做得更保守一些。

四、合规采集的原则与边界

在开始编写采集代码之前,必须先明确合规红线。很多数据分析师容易陷入一个误区:认为「只要数据是公开的,就可以随意抓取」。实际上,数据公开不等于抓取行为不受约束。合规采集至少要关注以下几个方面。

4.1 尊重 robots 协议与服务条款

访问任何网站之前,应先查看其 robots.txt 文件,确认目标路径是否允许自动化抓取。虽然 robots.txt 在法律上通常不被视为具有强制约束力的合同,但在实践层面,遵守它既是行业通行礼貌,也能降低法律风险。同时,要仔细阅读数据来源网站的服务条款,如果条款中明确禁止自动化采集,则应放弃程序化抓取,改用官方提供的 API 或人工下载。

4.2 坚持低频、少量、非侵入式原则

电力能源公开数据大多是月度或日度更新的统计信息,并不需要高频刷新。一个设计合理的采集流程,每天执行一次甚至每周执行一次就足够了。切忌设置过高频率的轮询,更不要并发打满数据源服务器。采集的数据范围应严格限定在分析所需字段,不要为了「先存下来再说」而过度抓取。

4.3 优先使用官方 API 和公开文件

如果数据源提供了官方 API 接口,应优先使用 API 而不是解析 HTML 页面。API 响应结构清晰、字段稳定,对数据源服务器的压力也更小。同样,如果能直接下载 Excel 或 CSV 文件,就不要去爬取网页表格。本文后续示例会优先采用公开文件下载和 JSON 接口两种方式。

4.4 数据使用的边界

采集到的公开数据主要用于内部研究、分析和决策支持。如果要将数据对外发布、商用或二次分发,需要进一步确认数据的授权范围。部分统计数据的转载和引用需要注明来源,个别数据可能附有额外的使用限制。在分析报告的末尾统一注明数据来源和采集时间,既是对数据提供方的尊重,也是专业素养的体现。

4.5 异常情况处理

如果采集过程中遇到数据格式变化、访问受限或返回异常,应先暂停任务,通过人工核对数据源页面确认原因,再决定是否调整采集策略。不要把「绕过限制」当作技术能力的体现。真正有价值的工作,是在合规前提下把数据工程做扎实。

五、采集架构设计

明确了数据源和合规边界之后,就可以开始设计采集架构。本文的目标是生成一份区域能源供需分析报告,因此采集架构需要覆盖电价、发电量、用电量和少量宏观变量四类数据,整体设计遵循「配置驱动、模块分离、失败重试、结果可追溯」的原则。

5.1 总体流程

整个数据链路可以拆分为五个阶段:

  1. 任务调度:按照配置好的时间触发采集任务。
  2. 数据采集:各采集器依次执行,从公开渠道获取原始数据。
  3. 数据清洗:对原始数据进行字段重命名、类型转换、单位统一和异常值处理。
  4. 指标计算:基于清洗后的数据计算供需平衡指标和趋势指标。
  5. 报告生成:把分析结果渲染为图文报告并输出。

5.2 采集器设计

每个数据源对应一个独立的采集器类,统一继承自 OpenClaw 的 Collector 基类。采集器的核心方法包括 fetch、parse 和 save 三个步骤:fetch 负责获取原始内容,parse 负责把内容解析成规范化数据,save 负责把数据写入存储。这种三段式设计便于单独测试和复用。

python 复制代码
from openclaw import Collector, RequestContext
from openclaw.storage import SqliteStorage
import pandas as pd


class BaseEnergyCollector(Collector):
    """电力能源数据采集器基类"""

    source_name = "base"
    data_type = "raw"

    def __init__(self, config, storage):
        super().__init__(config)
        self.storage = storage

    def fetch(self):
        raise NotImplementedError

    def parse(self, raw_data):
        raise NotImplementedError

    def save(self, df: pd.DataFrame):
        self.storage.write_dataframe(self.source_name, df, if_exists="append")

这个基类把存储逻辑统一封装起来,子类只需要实现 fetch 和 parse 即可。用 pandas 的 DataFrame 作为中间数据结构,可以很方便地和清洗模块衔接。

5.3 存储设计

对于中小规模的项目,SQLite 数据库足够满足需求。可以按照数据类别建立独立的表,例如 electricity_price、power_generation、power_consumption、installed_capacity 等。每张表统一保留 source、region、period、collected_at 四个元数据字段,用于追溯每条数据的来源和采集时间。

sql 复制代码
CREATE TABLE electricity_price (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    region TEXT NOT NULL,
    period TEXT NOT NULL,
    price_type TEXT,
    peak_price REAL,
    flat_price REAL,
    valley_price REAL,
    source TEXT,
    collected_at TEXT
);

这种设计虽然简单,但足以支撑区域尺度的分析需求。如果后续数据量增长到百万行以上,再把存储切换为 PostgreSQL 等数据库,OpenClaw 的存储层支持通过配置切换后端,业务代码无需大幅改动。

5.4 容错与限速

采集任务在执行过程中可能遇到网络超时、页面结构变化、文件不存在等各类异常。合理的做法是:为每个采集器配置独立的异常处理逻辑;对网络类异常进行有限次数的重试;重试仍失败时记录错误日志并跳过,不影响其他采集器运行。同时,通过配置中的 min_interval 控制请求频率,在批量采集时加入随机抖动,避免固定间隔带来的周期性峰值。

六、实操一:电网分时电价数据采集

电价数据是区域能源供需分析中敏感性最高、也最受关注的一类数据。本节的采集目标有三类:省级电网代理购电价格表、工商业分时电价政策参数、电力市场月度交易均价。其中,分时电价政策参数往往是理解区域电价结构的基础,下面以此为例进行完整演示。

6.1 数据来源与结构分析

以某省发改委发布的分时电价政策文件为例,公开页面上通常会包含一张分时段电价表,字段包括:时段类型(尖峰、高峰、平段、低谷、深谷)、时段范围、电度电价、基本电价等。采集前先用浏览器开发者工具查看页面结构,确认表格所在的 HTML 标签,以及是否提供了 Excel 附件下载。

如果页面提供 Excel 附件,优先下载附件。假设附件地址可以稳定访问,采集代码如下:

python 复制代码
import requests
import pandas as pd
from pathlib import Path


class TimeOfUsePriceCollector:
    """分时电价采集器:从公开 Excel 文件下载并解析"""

    def __init__(self, file_url, save_dir="raw_data"):
        self.file_url = file_url
        self.save_dir = Path(save_dir)
        self.save_dir.mkdir(exist_ok=True)

    def fetch(self):
        headers = {
            "User-Agent": "Mozilla/5.0 (compatible; EnergyDataCollector/1.0)"
        }
        resp = requests.get(self.file_url, headers=headers, timeout=30)
        resp.raise_for_status()
        local_file = self.save_dir / "time_of_use_price.xlsx"
        local_file.write_bytes(resp.content)
        return local_file

    def parse(self, local_file):
        df = pd.read_excel(local_file, sheet_name=0, header=1)
        df = df.rename(columns={
            "时段类型": "time_type",
            "时段范围": "time_range",
            "电度电价": "energy_price",
            "基本电价": "base_price",
        })
        df["currency"] = "CNY"
        df["price_unit"] = "yuan_per_kwh"
        return df

这段代码的核心思路很简单:下载文件到本地,再用 pandas 读取指定工作表,并对列名进行标准化。header 参数需要根据实际文件的表头位置调整,通常第一次采集时可以先打印出前几行,确认表头在第几行。

6.2 对网页表格的备用方案

如果数据源没有提供 Excel 附件,只能解析 HTML 表格,可以使用 pandas 的 read_html 配合 OpenClaw 的页面抓取能力。但需要注意,read_html 对表格结构比较敏感,合并单元格和嵌套表格容易导致解析错乱,因此解析后必须进行人工校验。

python 复制代码
from openclaw.http import fetch_page
import pandas as pd


def parse_price_table_from_html(page_url: str):
    """从公开网页解析分时电价表"""
    html = fetch_page(page_url, timeout=30)
    tables = pd.read_html(html)
    if not tables:
        raise ValueError("未在页面中找到表格")
    df = tables[0]
    df.columns = [str(c).strip() for c in df.columns]
    return df

解析完成后,建议先把结果导出为 CSV 并人工抽查几行,确认时段划分和价格数值没有错位,再进行后续入库操作。

6.3 数据验证与入库

采到的电价数据在入库前应当通过基础校验,例如:价格必须为大于零的数值;尖峰价格理论上应大于或等于高峰价格,高峰价格大于或等于平段价格,平段价格大于或等于低谷价格。如果校验不通过,说明存在解析错误或数据源异常,需要重新检查。

python 复制代码
def validate_price_data(df: pd.DataFrame):
    """校验分时电价数据的合理性"""
    required_cols = {"time_type", "energy_price"}
    missing = required_cols - set(df.columns)
    if missing:
        raise ValueError(f"缺少必要字段: {missing}")

    if (df["energy_price"] <= 0).any():
        raise ValueError("存在非正数电价,请检查原始数据")

    order = {"尖峰": 4, "高峰": 3, "平段": 2, "低谷": 1, "深谷": 0}
    if "time_type" in df.columns:
        levels = df["time_type"].map(order).dropna()
        if levels.is_monotonic_decreasing is False and len(levels) > 1:
            pass
    return True

对电网代理购电价格,同样的思路也适用。代理购电价格表通常按月发布,字段包括各类用户对应的电度电价和基本电价。建议按月份建表保存,形成时间序列,便于后续观察价格月度变化。

七、实操二:发电量与发电结构数据采集

发电量数据是判断区域电力供给能力的基础。本节的采集目标是分类别发电量月度数据,包括火电、水电、风电、太阳能发电和核电五个主要类别,同时采集累计装机容量,用于计算发电设备利用小时数。

7.1 数据来源与字段说明

国家能源局和中电联的公开月报是发电量数据最权威的来源。这些数据通常以「全国电力工业统计数据」表单形式发布,字段包括:指标名称、单位、本月、本月增速、累计、累计增速等。对于区域分析,需要重点提取目标省份对应的行。

python 复制代码
import pandas as pd
from openclaw.http import fetch_page


class GenerationCollector:
    """发电量数据采集器:解析公开统计页表格"""

    base_url = "https://example-gov-site.example/energy"

    def fetch(self, month: str):
        url = f"{self.base_url}/power_industry_{month}.html"
        html = fetch_page(url, timeout=30)
        tables = pd.read_html(html)
        if not tables:
            raise ValueError("页面未找到数据表格")
        return tables

    def parse(self, tables):
        df = None
        for table in tables:
            flat_cols = [str(c).strip() for c in table.columns]
            if any("发电量" in c for c in flat_cols):
                df = table.copy()
                break
        if df is None:
            raise ValueError("未找到发电量相关表格")

        df.columns = ["metric", "unit", "current_value",
                      "current_yoy", "cumulative_value", "cumulative_yoy"]
        return df

这段代码先抓取页面并提取全部表格,然后根据表头是否包含「发电量」来筛选目标表格。实际项目中,数据源页面的表格结构和列数可能随月份调整,因此解析逻辑要预留一定的容错空间,例如对列名做模糊匹配、对缺失列进行补空。

7.2 结构提取与长表转换

很多官方统计表采用「宽表」结构,一行对应一个指标,多个月份或地区的数据分散在不同列中。这种结构适合浏览,但不适合入库分析。建议在解析后把宽表转换为标准的「长表」结构,即每行只包含一个地区、一个月份、一个指标和一个数值。

python 复制代码
def wide_to_long(df: pd.DataFrame, region: str, period: str):
    """把宽表转换为标准长表"""
    records = []
    for _, row in df.iterrows():
        metric = row.get("metric")
        value = row.get("current_value")
        yoy = row.get("current_yoy")
        if metric and value is not None:
            records.append({
                "region": region,
                "period": period,
                "metric": metric,
                "value": float(value),
                "yoy": yoy,
            })
    return pd.DataFrame(records)

长表结构的好处是,后续无论是按地区横向对比,还是按时间纵向观察,都可以直接使用 pandas 的透视和分组操作,不需要再反复处理列名。

7.3 装机容量数据的采集

装机容量用于衡量区域发电能力规模。统计口径通常包括累计装机容量和新增装机容量两个指标,按火电、水电、风电、太阳能发电、核电分类。采集方式与发电量类似,唯一需要注意的是单位可能为万千瓦,分析时需要统一换算为千瓦或兆瓦,避免不同数据源单位不一致导致计算错误。

python 复制代码
UNIT_MAP = {
    "万千瓦": 10_000,
    "兆瓦": 1_000,
    "千瓦": 1,
}


def normalize_capacity(value: float, unit: str):
    """把装机容量统一换算为千瓦"""
    factor = UNIT_MAP.get(unit)
    if factor is None:
        raise ValueError(f"未知单位: {unit}")
    return value * factor

在数据入库时,建议同时保留原始数值和标准化后的数值,既可以追溯原始口径,又方便后续计算。

八、数据清洗与标准化

采集回来的原始数据往往存在各种问题:字段名不一致、单位混用、缺失值、明显异常值、文本和数值混杂。清洗环节的目标是形成一套干净、一致、可直接用于计算的规范化数据。

8.1 字段与单位标准化

首先制定一套统一的字段命名规范和单位规范。例如:region 统一使用省级行政区标准名称;period 统一为 YYYY-MM 格式;发电量单位统一为亿千瓦时;用电量单位统一为亿千瓦时;装机容量单位统一为万千瓦;电价单位统一为元每千瓦时。所有采集器在入库前都按照这套规范转换,可以在源头减少后续混乱。

python 复制代码
import re
import pandas as pd


def normalize_period(value):
    """把各种时间表达统一为 YYYY-MM"""
    text = str(value).strip()
    m = re.match(r"(\d{4})年(\d{1,2})月", text)
    if m:
        return f"{int(m.group(1)):04d}-{int(m.group(2)):02d}"
    m = re.match(r"(\d{4})-(\d{1,2})", text)
    if m:
        return f"{int(m.group(1)):04d}-{int(m.group(2)):02d}"
    return text


def safe_float(value):
    """容忍逗号、百分号等常见噪声的数值转换"""
    if value is None:
        return None
    if isinstance(value, (int, float)):
        return float(value)
    text = str(value).replace(",", "").replace(",", "").strip()
    text = text.replace("%", "")
    try:
        return float(text)
    except ValueError:
        return None

8.2 去重与冲突处理

由于同一指标可能从多个渠道采集,去重必不可少。可以用 region、period、metric 三个字段组成唯一键,对重复记录进行合并。当不同来源的数据存在冲突时,建议按照来源优先级取数,例如官方直接发布的文件优先于第三方转载,并在日志中记录冲突情况,便于后续审计。

python 复制代码
def deduplicate(df: pd.DataFrame, key_cols):
    """去重并保留优先级最高的来源"""
    df = df.sort_values("source_priority", ascending=True)
    df = df.drop_duplicates(subset=key_cols, keep="first")
    return df

8.3 异常值检测

异常值检测可以采用简单有效的规则:数值超出合理范围即标记为异常。例如,发电量同比增速通常在 -50% 到 100% 之间,超出这个范围很可能存在单位或解析错误;分类别发电量不应高于全口径发电量;区域用电量不应为负。对于标记为异常的数据,不应直接删除,而是先暂停入库并输出到待人工审核的列表中。

python 复制代码
def detect_outliers(df: pd.DataFrame):
    """基于规则检测异常值"""
    flags = []
    if "yoy" in df.columns:
        yoy = pd.to_numeric(df["yoy"], errors="coerce")
        flags.append((yoy < -50) | (yoy > 100))
    if "value" in df.columns:
        flags.append(df["value"] < 0)
    if flags:
        combined = flags[0]
        for flag in flags[1:]:
            combined = combined | flag
        df = df.assign(is_outlier=combined)
    return df

清洗后的数据写入数据库,并同时输出一份「数据质量报告」,记录每个来源的数据行数、缺失率、异常数量和去重情况。这份报告可以作为整个数据链路健康度的观察指标。

九、区域能源供需分析模型构建

数据准备就绪后,就可以进入分析环节。区域能源供需分析的核心思路,是从供给和需求两侧分别建立时间序列,再通过供需平衡指标观察两者之间的相互关系。

9.1 供给能力指标

供给能力可以从绝对量和结构两个维度刻画。绝对量方面,用月度分类别发电量、累计发电量、总装机容量表示;结构方面,计算各电源类型的发电量占比和装机占比,观察区域电力供给的清洁化程度。发电设备利用小时数是一个综合效率指标,计算公式为:

发电设备利用小时数 = 发电量 ÷ 平均装机容量

利用小时数越高,说明发电设备运行越充分;不同类型电源的利用小时数差异,也能反映出资源禀赋和调度方式的差异。

9.2 需求强度指标

需求侧重点观察全社会用电量的总量和增速。分产业用电量可以进一步揭示增长动力来自工业还是居民生活。如果数据可得,还可以引入最高负荷和峰谷差,描述电力需求的时间分布特征。用电量与工业增加值之间的相关性,是判断区域经济与电力消费联动关系的常用方法。

python 复制代码
def calc_supply_demand_metrics(gen_df, con_df, cap_df):
    """计算供需分析核心指标"""
    supply = gen_df.groupby(["region", "period"])["value"].sum().reset_index()
    supply = supply.rename(columns={"value": "total_generation"})

    demand = con_df.groupby(["region", "period"])["value"].sum().reset_index()
    demand = demand.rename(columns={"value": "total_consumption"})

    merged = supply.merge(demand, on=["region", "period"], how="outer")
    merged["supply_demand_ratio"] = (
        merged["total_generation"] / merged["total_consumption"]
    )
    merged["gap"] = (
        merged["total_generation"] - merged["total_consumption"]
    )

    cap_total = cap_df.groupby(["region", "period"])["value"].sum().reset_index()
    cap_total = cap_total.rename(columns={"value": "total_capacity"})
    merged = merged.merge(cap_total, on=["region", "period"], how="left")

    merged["utilization_hours"] = (
        merged["total_generation"] / merged["total_capacity"]
    )
    return merged

9.3 供需平衡判断

供需平衡比是区域电力供需松紧程度的一个简化代理指标。电力系统的实际供需平衡还涉及跨区输电、电力进出口和需求侧响应等复杂因素,因此单一区域的发电量与用电量之差,在解读时需要格外谨慎。对于跨区送受电占比高的省份,本地发电量可能显著小于用电量,但这并不意味着供需紧张,因为外来电承担了部分供给。

更稳健的分析方式,是把供需平衡比与市场交易价格、最高负荷等指标结合起来观察。当某区域用电量增速持续高于发电量增速,同时市场交易均价走强、峰谷差扩大时,可以认为该区域电力供需趋紧;反之则趋于宽松。

9.4 趋势与结构分析

在指标计算的基础上,可以进一步做同比、环比和累计增速分析,观察各项指标的运行轨迹。以发电量为例,可以计算近十二个月的移动平均,过滤月度波动,更清晰地识别趋势变化。结构分析方面,重点是新能源发电量占比的变化,这与区域能源转型进程直接相关。

python 复制代码
def calc_trends(df: pd.DataFrame, window: int = 3):
    """计算同比、环比和移动平均"""
    df = df.sort_values(["region", "period"])
    df["mom_change"] = df.groupby("region")["value"].pct_change()
    df["yoy_change"] = df.groupby("region")["value"].pct_change(periods=12)
    df["ma"] = (
        df.groupby("region")["value"]
        .transform(lambda x: x.rolling(window, min_periods=1).mean())
    )
    return df

分析时要特别注意口径的一致性。例如,使用年度累计值和月度值计算同比时,两者口径不同会导致错误结论;发电量与用电量的单位是否统一、是否包含厂用电和线损,也需要在比较前核对清楚。

十、生成自动化分析报告

分析的价值最终要落到可读、可执行的报告上。一份区域能源供需分析报告通常包含以下板块:核心结论摘要、供给能力分析、需求变化分析、电价趋势分析、供需平衡判断、风险提示和附录数据表。

10.1 报告模板设计

报告可以采用 HTML 模板生成,便于在富文本编辑器、邮件或内部系统中直接查看,也方便后续转换为 PDF 发布。模板中定义好报告头部、各分析板块和图表插入位置,数据通过模板引擎填充。

python 复制代码
from openclaw.report import ReportBuilder


class EnergyReportBuilder(ReportBuilder):
    """区域能源供需分析报告构建器"""

    def build(self, analysis_results, region, period):
        report = {
            "title": f"{region}区域能源供需分析报告({period})",
            "generated_at": analysis_results["generated_at"],
            "sections": [
                {
                    "heading": "一、核心结论",
                    "content": self.render_summary(analysis_results["summary"]),
                },
                {
                    "heading": "二、供给能力分析",
                    "content": self.render_supply(analysis_results["supply"]),
                },
                {
                    "heading": "三、需求变化分析",
                    "content": self.render_demand(analysis_results["demand"]),
                },
                {
                    "heading": "四、电价趋势分析",
                    "content": self.render_price(analysis_results["price"]),
                },
                {
                    "heading": "五、供需平衡判断",
                    "content": self.render_balance(analysis_results["balance"]),
                },
                {
                    "heading": "六、风险提示",
                    "content": self.render_risks(analysis_results["risks"]),
                },
            ],
        }
        return self.render_html(report)

10.2 可视化图表

图表是报告中最直观的部分。可以用 matplotlib 或更现代的图表库生成静态图片,再把图片嵌入 HTML 报告。常用的图表类型包括:分类别发电量堆叠柱状图、用电量趋势折线图、发电结构占比环形图、电价月度变化柱状图、供需平衡比走势图。

python 复制代码
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt


def plot_generation_structure(df: pd.DataFrame, output_path: str):
    """绘制分类别发电量结构图"""
    pivot = df.pivot_table(
        index="period",
        columns="source_type",
        values="value",
        aggfunc="sum",
    )
    fig, ax = plt.subplots(figsize=(10, 5))
    pivot.plot(kind="bar", stacked=True, ax=ax)
    ax.set_title("分类别发电量结构")
    ax.set_xlabel("月份")
    ax.set_ylabel("发电量(亿千瓦时)")
    ax.legend(title="电源类型")
    plt.tight_layout()
    fig.savefig(output_path, dpi=150)
    plt.close(fig)

图表生成后,把图片路径写入报告模板,并在报告中注明数据口径和单位,防止读者误解。

10.3 报告中的关键结论

报告的核心结论应当简明扼要,直接回答三个问题:供给是否充足、需求是否旺盛、价格是否上涨。不要堆砌数据,而要给出可操作的判断。例如:

本期区域全口径发电量同比增长 4.2%,其中风电、光伏发电量合计同比增长 18.6%,清洁能源占比提升 2.3 个百分点;全社会用电量同比增长 5.1%,第三产业和居民生活用电是主要拉动力;代理购电均价环比持平,峰谷价差较上月收窄。综合判断,区域电力供需总体平衡,新能源出力波动对高峰时段的保供压力仍需关注。

10.4 自动化调度与发布

报告生成后,可以接入定时调度,例如每月初自动采集上月数据并生成报告,再通过邮件或内部系统推送给相关同事。调度配置可以在 config.yaml 中统一管理,也可以使用操作系统级的 cron 任务调用 main.py

bash 复制代码
0 9 3 * * cd /path/to/energy-report && /path/to/energy_env/bin/python main.py --month $(date -d "last month" +%Y-%m)

自动化报告的价值在于降低重复劳动,但首次上线前必须经过一段时间的「影子运行」,即自动生成报告与人工核对并行,确认数据口径和结论准确后再正式替代人工流程。

十一、完整项目示例代码

为了便于读者快速落地,下面给出一个精简但完整的项目入口代码,把前文介绍的采集、清洗、分析和报告生成串联起来。需要注意的是,示例中的网址和数据源路径均为演示占位,实际使用时请替换为真实可访问的公开数据地址。

python 复制代码
import logging
import pandas as pd
from pathlib import Path

from openclaw import Config, Project
from collectors.price_collector import TimeOfUsePriceCollector
from collectors.generation_collector import GenerationCollector
from collectors.demand_collector import DemandCollector
from processors.cleaner import clean_price, clean_generation, clean_demand
from processors.analyzer import build_analysis
from openclaw.report import ReportBuilder

logging.basicConfig(level=logging.INFO,
                    format="%(asctime)s [%(levelname)s] %(message)s")


def run_pipeline(region: str, month: str):
    config = Config.load("config.yaml")
    project = Project(config)

    logging.info("开始采集电价数据")
    price_raw = TimeOfUsePriceCollector(config).run()

    logging.info("开始采集发电量数据")
    gen_raw = GenerationCollector(config).run(month)

    logging.info("开始采集用电量数据")
    demand_raw = DemandCollector(config).run(month)

    logging.info("清洗数据")
    price_clean = clean_price(price_raw)
    gen_clean = clean_generation(gen_raw)
    demand_clean = clean_demand(demand_raw)

    logging.info("写入存储")
    project.storage.save("price", price_clean)
    project.storage.save("generation", gen_clean)
    project.storage.save("demand", demand_clean)

    logging.info("计算分析指标")
    analysis = build_analysis(region, month, project.storage)

    logging.info("生成报告")
    report = ReportBuilder().render(analysis)
    output_file = Path("reports") / f"energy_report_{region}_{month}.html"
    output_file.parent.mkdir(exist_ok=True)
    output_file.write_text(report, encoding="utf-8")

    logging.info("报告已生成: %s", output_file)


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="区域能源供需分析报告生成工具")
    parser.add_argument("--region", required=True, help="目标区域名称")
    parser.add_argument("--month", required=True, help="分析月份,格式 YYYY-MM")
    args = parser.parse_args()

    run_pipeline(args.region, args.month)

这个入口代码把整个流程封装为命令行工具,便于定时任务调用。运行示例:

bash 复制代码
python main.py --region east-china --month 2026-08

项目首次运行时,建议先调试单个采集器,确认每条数据链路都打通后,再整体运行。调试阶段的日志可以设置得详细一些,便于定位问题;生产运行时则保留必要日志,避免日志文件过快膨胀。

十二、合规风险控制与持续优化

数据采集项目上线不是终点,持续的合规审查和链路维护同样重要。公开数据源的页面结构可能随时调整,政策文件可能被替换或下架,流量限制策略也可能变化。以下几条实践经验值得长期坚持。

12.1 建立数据源台账

为每一个数据源建立台账,记录 URL、字段口径、更新频率、访问规则、robots 约定、负责人和最近一次核验时间。台账不是一次性文档,而应当随数据源变化动态更新。团队新成员接手时,台账是最高效的交接材料。

12.2 定期核验数据质量

自动化脚本能发现问题,但不能替代人工判断。建议每月在自动报告生成后,由分析人员对关键数字做一次「合理性抽查」,与官方发布的新闻稿、统计快报进行交叉验证。一旦发现偏离,立即追溯到具体采集环节排查原因。

12.3 保持采集策略的克制

数据采集的频率和数量应当遵循「够用就好」的原则。对于月度分析场景,每月一次采集完全足够,不需要为了追求所谓的实时性而高频轮询。遇到数据源更新滞后时,宁可等待官方发布,也不要尝试通过非常规手段抢先获取。

12.4 版本管理与可复现性

采集代码、清洗规则和分析模型都应当纳入 Git 版本管理。数据入库时记录代码版本号,确保任何一份历史报告都能在需要时完整复现。分析口径的每次调整都要有变更说明,并在报告附录中注明所采用的口径版本。

12.5 关注政策与规则变化

电力能源领域政策密集,电价机制、统计口径和数据发布方式都可能调整。采集人员需要保持对相关政策文件和行业动态的关注,并定期检查数据源网站是否更新了服务条款或改版。数据工程与领域知识的结合,是这类项目长期有效运转的根本保障。

十三、总结与展望

本文围绕电力能源公开数据采集与分析这一主题,从数据源盘点、环境搭建、合规原则、架构设计,到电价和发电量两类数据的采集实操、清洗标准化、供需分析建模和报告自动生成,完整展示了一条可落地的技术路径。核心经验可以归纳为三点:先摸清数据源再写代码,先定好合规边界再设计架构,先保证数据质量再谈模型和自动化。

OpenClaw 作为数据采集与处理框架,在本项目中承担了任务编排、请求管理、数据存储和报告渲染等基础能力,使得开发者可以把精力集中在数据源的对接和业务指标的计算上。代码中的大部分示例都保持了解耦和可替换性,即使未来切换到其他采集框架或数据库,核心的分析思路依然适用。

从更长远的角度看,区域能源供需分析还有不少值得深入的方向:引入气象数据构建用电负荷预测模型,结合电力现货市场价格研究价差套利策略,利用碳排放因子数据评估电源结构转型的环境效益,以及将分析结果接入企业能源管理系统形成闭环决策。随着电力市场化改革和能源数字化转型的深入,公开数据与数据分析能力的结合将释放出更大的价值。希望本文的方法和示例,能为读者在能源数据领域的工作提供一份实用参考。

相关推荐
应用市场44 分钟前
GPT vs Claude 深度对比(2026年9月):从模型特性到编程实战,开发者该怎么选
python·gpt·flask
一切皆是因缘际会1 小时前
资源的适配
大数据·人工智能·算法
计算机编程-吉哥1 小时前
小麦叶病害识别系统:基于MobileNet的智能农业病害检测实战【计算机毕业设计选题推荐、深度学习】
人工智能·深度学习·毕业设计·课程设计·计算机毕业设计选题·机器学习毕业设计·大数据毕业设计选题推荐
IT毕设实战小研1 小时前
基于大数据的WTA职业网球赛事演变与竞技格局数据可视化分析
大数据·后端·爬虫·python·信息可视化·课程设计
新知图书1 小时前
第11章 智能体应用设计模式
人工智能·智能体
veminhe1 小时前
python发送邮件带附件
python
LlmCraft|大模型工程实践1 小时前
09 大语言模型(LLM)演进与 Prompt 入门
人工智能·语言模型·prompt
zhanghaha13141 小时前
Python进阶教程:28_queue 队列模块 零基础超详细教程
java·开发语言·python
刘广睿1 小时前
AI 配音怎么做?语音合成 TTS 技术选型与本地部署实战(edge-tts / GPT-SoVITS / CosyVoice / Piper)
人工智能·音视频·效率工具·语音合成·tts