ARTICLE DETAIL

资讯详情

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

2006-2024机场生产统计公报数据采集与数据集构建实战解析

2006-2024机场生产统计公报数据采集与数据集构建实战解析 干民航数据分析这行的人对《全国民用运输机场生产统计公报》应该都不陌生。我这次做的项目就是把2006到2024这19个年度的公报完整采集下来清洗入库整理成一套能直接查询、能跑分析、能复现的机场生产数据集。乍一听好像只是下载文件、抄几个数字的事但真正动手之后才发现从数据源识别、字段口径统一到历史数据断档修补、异常值校验每一步都有讲究。这篇博文就把整个数据获取和处理过程完整拆开讲一遍包括数据源选择、库表设计、清洗规则、分析脚本和踩过的坑给打算做民航统计或区域经济研究的朋友一份可以直接参考的作业。1. 项目拆解为什么要把19年的公报建成数据集先把项目定位说清楚。全国民用运输机场生产统计公报是民航局每年对外发布的核心统计文件覆盖每个运输机场的旅客吞吐量、货邮吞吐量和起降架次。这三项指标看起来简单却是观察民航业景气度、区域经济活力、机场建设节奏的最直接窗口。1.1 公报的核心字段与数据价值公报经过多个版本迭代之后字段结构基本稳定在主表加附表的形式。主表是全国所有运输机场的总量汇总附表则按机场逐行列出旅客吞吐量、货邮吞吐量、起降架次以及和上一年相比的增速。具体到每个机场核心字段包括机场名称和所在省份旅客吞吐量人次货邮吞吐量吨起降架次架次同比增长率%排名变化为什么这些数据值得做成长周期的数据集因为单一年的公报只能看到截面而19年跨度能看出完整周期。2006年的时候全国运输机场还不到150个到2024年已经超过260个北京首都机场的旅客吞吐量在2019年突破1亿人次后面又经历了特殊时期的断崖下跌和缓慢爬坡。这些波动单独看某一年可能只觉得是数字变化放进时间序列里才能识别出真实的结构性增长和异常事件的影响。这也是我坚持要把数据建库而不是散存Excel的根本原因。1.2 项目目标与交付形态这个项目的目标很明确把2006到2024年的公报整合成一套结构化、可分析、可持续更新的数据集。交付物分成三块第一原始文件留档。每个年度的公报原文包括PDF和网页版本按年份归档命名规则统一为公报_年份_来源渠道。第二标准化数据表。一张明细表记录每个机场每年的生产数据一张维度表记录机场基础属性名称、省份、城市、是否军民合用等两张表通过机场ID关联。第三分析脚本和可视化模板。包括数据清洗脚本、指标汇总脚本和一组常用图表比如头部机场排名变化、各省总吞吐量趋势、增速分布直方图。说白了这个项目的本质不是“下载文件”而是把非结构化的公报内容拆解成规范的数据资产。后面所有分析工作都建立在第三块的基础上所以数据质量校验必须前置否则后面分析全是白搭。2. 数据源与获取渠道解析很多人第一步就卡在去哪找数据。民航局官网的统计信息栏目是唯一的权威源头但实际操作中数据发布位置、文件格式和更新节奏都有规律可循。2.1 官方发布渠道详解《全国民用运输机场生产统计公报》一般在每年第一季度发布上一年度的数据最晚不超过3月底。发布渠道主要有两个一个是民航局官网的“统计信息”栏目公报以HTML网页和附件的形式呈现附件通常是PDF或Excel。另一个是中国民航统计年鉴作为补充但年鉴出版滞后、覆盖面更广不适合做快速更新。我的经验是优先盯官网的发布时间节点。每年1月初开始在搜索引擎和民航局官网用“机场生产统计公报年份”关键词轮询一旦官网挂出第一时间下载保存。因为部分年度的附件链接存在会被替换更新的情况晚几天下载可能拿到的是修订版而修订版和初始版之间的数据差异往往只在脚注里说明。2.2 数据格式对比与选型不同年份的公报格式差异非常大这也是项目里比较耗时的部分。我把2006到2024年的格式演变梳理成一张表阶段年份范围主要格式字段完整度处理难度早期2006-2010HTML表格 PDF字段较少仅有吞吐量、架次、排名较难需从网页提取或PDF转表格中期2011-2018HTML Excel附件字段扩展到投资完成额等中等Excel可直接读取近期2019-2024HTML Excel PDF字段完善含增速、占全国比重、排名变化较易结构化程度高选型的核心原则是优先读取Excel附件其次是HTML表格最后才考虑PDF。原因是民航局的Excel附件通常已经按规范的二维表结构组织省去大量解析工作HTML表格则需要处理标签噪声PDF虽然官方但版式复杂早期年份还经常以扫描件形式出现必须借助OCR才能转成可编辑文本效率低且容易引入识别错误。2.3 合规获取的边界做数据采集首先要明确边界。民航局的统计公报属于政府依法公开的统计信息面向社会公开发布个人下载、整理、分析、再发布都是合规的只需要在引用时注明数据来源。我建议所有文件下载后保留原始来源URL和下载时间一方面满足可溯源要求另一方面在数据校验时能快速定位差异。不要使用任何绕过访问限制的手段也不要去爬取官网之外的旅客量猜测数据。统计公报里的数字是官方口径其他渠道的数据因为统计范围不同直接混用会导致严重偏差。3. 采集与整理全流程实操数据源确定之后进入核心环节建库、提取、清洗、校验。这四步决定了最终数据集的质量。3.1 数据模型设计我选择MySQL作为存储数据库原因很简单机场数据量并不大19年260个机场约5000行MySQL完全够用而且周边生态成熟方便后续接BI工具或写Python脚本。库表结构按维度事实建模-- 机场维度表 CREATE TABLE dim_airport ( airport_id INT PRIMARY KEY AUTO_INCREMENT, airport_name VARCHAR(64) NOT NULL, province VARCHAR(32), city VARCHAR(32), airport_type VARCHAR(16), -- 民用/军民合用 is_current VARCHAR(8), -- 是否仍在运营 UNIQUE KEY uk_name (airport_name) ); -- 生产数据事实表 CREATE TABLE fact_airport_production ( stat_year INT NOT NULL, airport_id INT NOT NULL, passenger_volume BIGINT COMMENT 旅客吞吐量(人次), cargo_volume BIGINT COMMENT 货邮吞吐量(吨), flight_sorties INT COMMENT 起降架次(架次), passenger_yoy DECIMAL(8,4) COMMENT 旅客同比增速, cargo_yoy DECIMAL(8,4), flight_yoy DECIMAL(8,4), national_rank INT COMMENT 全国排名, update_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (stat_year, airport_id), KEY idx_year (stat_year) );这个模型的核心思路是把机场名称这类缓变维度独立出来避免主表数据冗余。特别要注意的是机场改名的情况比如广州白云机场名称没变但有些机场从“某某机场”改名为“某某国际机场”如果每次改名都当成新机场处理跨年排名对比就会断裂。所以我在维度表中增加is_current字段遇到名称变更时检查民航局官方更名文件保留一个机场ID名称用最新值。3.2 抓取、解析与入库数据入库的流程我用Python实现整体分为三步下载、解析、写入。下载部分优先用官方Excel附件。代码不算复杂import requests import pandas as pd from pathlib import Path def download_file(url, save_path): resp requests.get(url, timeout30, headers{ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) }) resp.raise_for_status() Path(save_path).write_bytes(resp.content) print(f已下载: {save_path}) # 示例下载2024年公报Excel附件 download_file(https://example.gov.cn/statistics/2024-airport-report.xlsx, data/公报_2024_官网.xlsx)再强调一次一定要维护一个下载清单记录每个年份的URL、文件MD5值和下载时间。民航局偶尔会在发现统计错误后静默更新附件没有MD5记录的话数据被更新了你都无法察觉。解析部分最关键的活是二维表转长表。民航局的Excel通常是宽表一个工作表里有多个区块一个区块是排名前50机场旅客吞吐量另一个区块是全部机场货邮吞吐量。直接用pandas读取再拆分即可df pd.read_excel(data/公报_2024_官网.xlsx, sheet_nameNone, headerNone) # 以旅客吞吐量表为例通常第7-8行是表头 for sheet_name, sheet_df in df.items(): print(sheet_name, sheet_df.shape)实际处理时每个年份的工作表布局都不一样所以不能硬编码行号。我采取的办法是把每个年份的解析逻辑封装成单独函数用一个配置项指明表头行、数据起始行、列名映射。虽然前期写配置比较繁琐但换来的是一劳永逸的可复现性明年新公报发布时只需新增一个配置不用重写核心代码。入库时注意类型转换。吞吐量字段需要处理Excel里的科学计数法比如对某些大数值pandas读进来可能显示为1.234568e07要显式转成整数百分比字段要处理文本形式的指标比如“增长5.2%”需要去掉百分号再转浮点。3.3 数据清洗与交叉校验清洗是数据质量的生命线。以民航数据为例我重点做三类清洗第一类是空值和缺失值处理。个别年份个别机场没有公布货邮吞吐量用NULL而不是0填充。因为NULL代表没有数据0代表数值为零含义完全不一样。比如某些支线机场当年没有货运业务官方给出的就是0如果把它也记成NULL统计就会失真。第二类是异常值检测。我用了一个简单的规则集发现即排查起降架次除以旅客吞吐量比值应该在合理区间一架次平均承载80到200名旅客左右如果某机场一架次只承载5人要么是通用航空混入统计要么是数据录入错误。旅客吞吐量同比增速超过100%的需要结合新开航线或新航站楼投运情况判断。货邮吞吐量出现负值除口径调整外的直接判为异常。第三类是跨年交叉校验。同一机场在上年度公报中排名为N在下年度公报的排名变化值应该是上年排名减去年排名。利用这个逻辑可以倒推校验下一年榜单的完整性。举个例子2023年某机场排名第312024年公报显示它“排名上升8位”那2024年它应该排第23如果在明细数据里排名不是23说明榜单提取有遗漏。3.4 数据校验脚本实现清洗和校验我统一放在一个脚本里每次跑批之后输出校验报告。核心代码片段如下import pandas as pd def validate_year_data(df, year): errors [] # 规则1吞吐量不能为负 neg_check df[(df[passenger_volume] 0) | (df[cargo_volume] 0)] if not neg_check.empty: errors.append(f{year}: 存在负值数据 {len(neg_check)}条) # 规则2客座效率合理性粗略 df[pax_per_flight] df[passenger_volume] / df[flight_sorties] unreasonable df[df[pax_per_flight] 5] if not unreasonable.empty: errors.append(f{year}: 单架次承运旅客异常偏低 {len(unreasonable)}条) print(unreasonable[[airport_name, passenger_volume, flight_sorties]]) # 规则3排名连续性 df_sorted df.sort_values(passenger_volume, ascendingFalse) df_sorted[expect_rank] range(1, len(df_sorted) 1) rank_diff df_sorted[df_sorted[expect_rank] ! df_sorted[national_rank]] if not rank_diff.empty: errors.append(f{year}: 排名不一致 {len(rank_diff)}条) return errors这个脚本每次更新数据后跑一遍把errors列表打印到日志里。我在实际项目里发现过好几次问题比如某一年公报里有两个机场名字完全相同、但分属不同省份直接按名称关联维度表会导致数据串行。所以代码里还加了省份维度的联合校验只有机场名和省份同时匹配才认为是同一个机场。4. 数据分析与可视化实战数据入库后最让人兴奋的部分就是跑分析了。这一节我给出三个可以直接复用的分析示例覆盖趋势分析、排名变化和结构占比。4.1 19年总量趋势看周期不看单点先算全国总量的逐年变化import pandas as pd import numpy as np # 读取数据 df pd.read_sql(SELECT * FROM fact_airport_production, engine) # 全国汇总 national df.groupby(stat_year).agg( total_passenger(passenger_volume, sum), total_cargo(cargo_volume, sum), total_flight(flight_sorties, sum), airport_count(airport_id, nunique) ).reset_index() # 计算同比增速 national[passenger_yoy] national[total_passenger].pct_change() * 100 national[cargo_yoy] national[total_cargo].pct_change() * 100 print(national.tail(5))从2006到2019全国旅客吞吐量从不到4亿人次增长到13亿人次以上2020到2022出现罕见的负增长2023到2024恢复性反弹。这些结论单看任何一年都无法形成判断放到19年的序列里才能看清民航业与宏观经济的强相关性。这里我要多说一句做总量趋势时机场数量变化会影响总量所以我还额外统计了单机场平均吞吐量这个指标剔除了机场数量扩张的因素更能反映存量机场的运营效率变化。4.2 头部机场竞争格局分析头部机场的位次变化是媒体和公众最关注的话题之一。我直接提取每年旅客吞吐量前十的机场构建一个交叉表看谁一直在头部谁在2019年后掉队top10_by_year {} for year in range(2006, 2025): year_data df[df[stat_year] year].sort_values( passenger_volume, ascendingFalse ).head(10) top10_by_year[year] year_data[airport_name].tolist() top10_panel pd.DataFrame.from_dict(top10_by_year, orientindex)从2006年的格局看北京首都、上海浦东、广州白云、上海虹桥、深圳宝安长期占据前五2019年北京大兴机场投运后北京首都机场的旅客量被分流2020年成都天府机场投运又改变了西南格局。这些位次变化背后的逻辑是城市群发展和机场基建周期数据本身已经把故事讲清楚了。4.3 机场运力分布里的“二八定律”我还计算了各机场占全国总量的比重看看头部集中度如何变化# 每年排名第一机场的旅客量占全国比重 share_top1 df[df[national_rank] 1].set_index(stat_year)[passenger_volume] / national.set_index(stat_year)[total_passenger] # 前10机场集中度CR10 def cr10(year): year_data df[df[stat_year] year].sort_values(passenger_volume, ascendingFalse) top10_sum year_data.head(10)[passenger_volume].sum() return top10_sum / year_data[passenger_volume].sum() cr10_series pd.Series({year: cr10(year) for year in range(2006, 2025)})计算结果显示前十大机场旅客吞吐量占全国的比重从2006年的55%左右逐步下降到近年的45%以下。这说明民航网络从高度集中于枢纽机场向多中心、均衡化方向演变二三线城市机场的贡献在提升。这类分析对机场投资评估、航线网络规划都很有参考价值。5. 常见问题与排查技巧实录数据获取过程中踩过的坑不少挑几个典型问题分享希望能帮后来人省点时间。5.1 机场名称变化导致关联失败这是最容易忽视的问题。典型案例如下2017年“新建机场”以“XX机场”名字入表同一年“XX机场”被暂停运营部分机场因牌照变更从“民用机场”变为“军民合用机场”但吞吐量统计口径不变解决办法是在维度表里维护曾用名字段并且在入库前做一遍别名映射。映射表从历年公报脚注中提取民航局的脚注会说明“因机场更名数据与去年同期不可比”之类的话这些信息就是更新维度表的重要依据。5.2 历史数据格式不统一2006到2008年的公报没有Excel附件只有HTML网页表格我用pd.read_html提取。但部分网页表格存在跨行合并单元格的情况比如一个机场占了两行第二行标注“其中国内航线”如果直接按行解析会把占位空值当作另一条记录。处理方案解析后做一次重复项检查凡是机场名称为空且上下行机场名相同的连续行合并处理。这个规则对多年数据都有效我把它固化在清洗脚本里。5.3 数据更新与版本追踪民航局官网的附件版本更新是隐藏的不确定因素。2023年我就遇到过一次公报Excel首次发布后一个多月官网悄然更新了数据更新版本调整了某机场的货邮吞吐量数值。因为我有MD5记录比对后发现异常才没有把过期数据带进分析。建议在项目中建立一个dataset_versions表记录每次导入的年份、文件名、MD5值、发布时间、导入时间和备注。数据血缘清晰回滚也方便。5.4 高峰时间抓取触发访问限制下载文件时如果使用并发请求有概率触发网站的反爬机制。我的方案是加一个下载间隔默认3秒同时启用重试机制import time import requests def safe_download(url, save_path, retries3, delay3): for i in range(retries): try: resp requests.get(url, timeout30) if resp.status_code 200: Path(save_path).write_bytes(resp.content) return True except requests.RequestException as e: print(f第{i1}次重试: {e}) time.sleep(delay) return False官方公开数据是鼓励下载的但单线程加延时是对目标站点的基本礼貌也能避免自己的IP被临时限制。5.5 数据口径变化运输机场 vs 通用航空机场公报名称明确写了“民用运输机场”不包含纯通用航空机场。但2019年以后个别年份把“运输机场”的定义扩展到“保障航班运行的机场”导致机场数量口径发生变化。分析前必须检查脚注避免直接跨年对比机场数量。6. 应用场景扩展这套数据能怎么用数据获取不是终点能用起来才体现价值。结合我自己的使用经验梳理几个可能的扩展方向。6.1 区域经济与城市研究机场吞吐量和地方经济活跃度高度相关。把这套数据与城市GDP、旅游收入、外贸额等公开统计做关联分析可以验证很多经济学直觉。比如旅游城市机场的旅客吞吐量对节假日政策更敏感口岸机场的货邮吞吐量与本地加工贸易有强相关性。这类交叉分析被用在很多区域研究报告中。6.2 机场运营与航线网络规划对民航从业者来说这套历史数据是容量规划的重要输入。一架飞机日均起降效率、某机场的旅客中转比例变化都隐含在“旅客吞吐量/起降架次”这个比值里。通过对比同类机场之间的效率差异可以为新开航线、时刻分配提供参考。6.3 学校课题与课程设计很多高校的交通运输、经济管理专业学生都在找“既有数据量又不过度复杂”的分析素材。这份机场生产统计数据集恰好满足条件数据免费、开源渠道清晰、字段含义明确、跨年跨度适合做时间序列分析。如果学校有数据挖掘或Python数据分析课程这套数据可以直接作为期末大作业的数据基础。我有一个朋友做过一个有趣的课题用2006到2024年的机场吞吐量排名变化模拟城市航空枢纽地位的迁移过程最后还画出了动态排名变化的动画图表。整个分析链路就是从这套数据延伸出去的。6.4 数据产品化更进一步可以把清洗后的数据封装成一个小型API或SQLite数据库文件供团队内部使用。我在项目后期把结果导出成了SQLite和CSV两种格式方便非技术同事用Excel或Tableau直接接数据做周报。这个做法可以推广到任何类似的数据项目。7. 最后几点实操建议采集之前先把字段口径摸清楚花一小时读公报正文的“统计范围”和“指标解释”强过入库后返工十小时。日常保留原始文件不要只留清洗后的结果。没有原始文件的清洗后数据可信度直接腰斩。每处理完一个年份随手做一次人工抽查。整个数据集不到5000行抽查两个机场的数值成本很低但能拦住低级错误。做趋势分析前先检查是否有机场更名、停运、新投运这些都会在时间序列上制造断点。处理办法是单独标记这类年份在图表上用注释说明而不是硬着头皮去平滑。民航数据是个小而精的领域公开数据源不多但质量很高。把2006到2024年的机场生产统计公报整理成结构化数据集之后我最大的感受是数据获取的价值不只是“拿到了”而是把官方散落的公告转成能支撑分析决策的资产。这个过程需要耐心也需要对数据本身的敬畏。每次跑完校验脚本看到零报错那种踏实感大概就是这个项目最有回报的时刻。
返回列表