爬虫作业记录:航班数据爬取与可视化分析全流程解析

部署运行你感兴趣的模型镜像

爬虫作业记录:航班数据爬取与可视化分析全流程解析

一、提示

本文所有数据均为网站公开数据,本文仅用于学术讨论和技术研究。

二、网站介绍

深圳机场航空物流网站:
https://logistics.szairport.com/#/air-route-network/FlightSchedule
公开展示了深圳机场的航空物流数据:
在这里插入图片描述

三、数据爬取模块

数据爬取是整个分析流程的基础,我们需要从目标网站获取结构化的航班信息。

首先通过浏览器分析接口,很容易可以找到接口为

https://logistics.szairport.com/air/logistics/api/v1/multiple/flight_query

发送的请求体:
发送的请求体
返回的数据也是标准的json格式,很容易解析:
返回数据

3.1 导入必要库

import requests
import json,time,datetime
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
  • requests:用于发送 HTTP 请求,获取网页数据
  • json:处理 JSON 格式数据
  • timedatetime:处理时间相关操作,实现按日期爬取
  • pandas:数据处理与分析的核心库
  • warnings:忽略不必要的警告信息,使输出更简洁

3.2 初始化数据存储结构

df = pd.DataFrame(columns=['航空公司/航班号','机型机型','计划起飞','实际起飞','出发地','计划到达','实际到达','经停地','到达地','状态','机位'])

创建一个空的 DataFrame,定义了将要爬取的所有字段,包括航班基本信息、时间信息、地点信息和状态信息等。

3.3 设置请求头和目标 URL

根据浏览器的请求构建headers

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
    "Accept-Encoding": "gzip, deflate, br",
    "Content-Type": "application/json;charset=utf-8",
    "device": "pc",
    "Origin": "https://logistics.szairport.com",
    "Connection": "keep-alive",
    "Referer": "https://logistics.szairport.com/",
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "Pragma": "no-cache",
    "Cache-Control": "no-cache"
}
# 航运数据接口
url = "https://logistics.szairport.com/air/logistics/api/v1/multiple/flight_query"
  • headers:模拟浏览器请求头信息,包含浏览器类型、支持的数据类型、编码方式等
  • url:目标数据接口,这是一个 POST 请求接口,用于获取航班数据

3.4 设置爬取日期范围

start_day = '2025-05-01'
end_day =  '2025-05-10'

end_day = datetime.datetime.strptime(end_day,'%Y-%m-%d')
tmp_day= datetime.datetime.strptime(start_day,'%Y-%m-%d')
  • 将字符串格式的日期转换为 datetime 对象,便于进行日期计算和循环
  • 设置了从 2025-05-01 到 2025-05-10 的爬取日期范围

3.5 核心爬取逻辑

while (end_day-tmp_day).days>-1:#构建循环
    print(tmp_day)
    for page in range(999):
        data = {
            "flight_type": "0",
            "flight_no": "",
            "city_start": "",
            "city_end": "",
            "flight_time": f"{tmp_day.year}-{tmp_day.month}-{tmp_day.day}",
            "page_index": page,
            "page_size": 10,
        }
        data = json.dumps(data)
        response = requests.post(url, headers=headers, data=data)
        dedejson = response.json()
        for tmp_data in dedejson['data']['page_list']:
            print({'航空公司/航班号':tmp_data['flight_no'],'机型':tmp_data['flightModel'],'计划起飞':tmp_data['planStartTime'],'实际起飞':tmp_data['actStartTime'],
                               '出发地':tmp_data['start_name'],'计划到达':tmp_data['planEndTime'],'实际到达':tmp_data['actEndTime'],'经停地':tmp_data['mid_name'],
                            '到达地':tmp_data['end_name'],'状态':tmp_data['flight_status'],'机位':tmp_data['remark1']})
            df = df._append({'航空公司/航班号':tmp_data['flight_no'],'机型':tmp_data['flightModel'],'计划起飞':tmp_data['planStartTime'],'实际起飞':tmp_data['actStartTime'],
                               '出发地':tmp_data['start_name'],'计划到达':tmp_data['planEndTime'],'实际到达':tmp_data['actEndTime'],'经停地':tmp_data['mid_name'],
                            '到达地':tmp_data['end_name'],'状态':tmp_data['flight_status'],'机位':tmp_data['remark1']},ignore_index=True)
        # time.sleep(5)
        if len(dedejson['data']['page_list'])<10: #如果条数小于十条就爬下一天的
            tmp_day = (tmp_day + datetime.timedelta(days=+1))
            break

这段代码实现了多日期、多页的航班数据爬取:

  1. 外层 while 循环:按日期遍历,从 start_day 到 end_day
  2. 内层 for 循环:按页码遍历,最多 999 页(实际会提前结束)
  3. data 字典:构造 POST 请求参数,包括航班类型、日期、页码等
  4. json.dumps(data):将参数转换为 JSON 字符串格式
  5. requests.post():发送 POST 请求获取数据
  6. 解析 JSON 响应,提取航班列表数据
  7. 遍历每条航班数据,将其添加到 DataFrame 中
  8. 终止条件:当某页返回的航班数小于 10 条(分页大小),说明当前日期数据已爬取完毕,切换到下一天

运行结果如下:
在这里插入图片描述
在这里插入图片描述

四、数据存储到 MongoDB

爬取到数据后,我们需要将其持久化存储,以便后续分析使用。这里选择 MongoDB 作为存储数据库。

4.1 导入 MongoDB 客户端库

from pymongo import MongoClient

pymongo 是 Python 操作 MongoDB 的官方驱动库。

4.2 连接数据库并创建集合

client = MongoClient('mongodb://localhost:27017/')  # 连接本地MongoDB服务
db = client['flight']  # 创建或使用名为'flight'的数据库
collection = db['flight']  # 创建或使用名为'flight'的集合
  • MongoDB 是文档型数据库,数据以 JSON 类似的文档形式存储
  • 这里假设 MongoDB 服务运行在本地,端口为默认的 27017

4.3 插入数据到 MongoDB

# 将DataFrame转换为字典列表
data = df.to_dict(orient='records')

# 插入数据到MongoDB中
collection.insert_many(data)

print("数据已成功插入到MongoDB中")
  • df.to_dict(orient='records'):将 DataFrame 转换为字典列表,每个字典代表一条航班记录
  • insert_many(data):批量插入多条记录,比单条插入效率更高

五、数据可视化分析

数据可视化是探索数据、发现规律的重要手段。下面将通过多种图表展示航班数据的不同维度。

5.1 航空公司航班准点率对比柱状图

import pandas as pd
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

# 计算总航班数
airline_ontime = df.groupby('航空公司/航班号').size().reset_index(name='总航班数')

# 计算准点航班数
on_time_flights = df[df['状态'] == '正常'].groupby('航空公司/航班号').size().reset_index(name='准点航班数')

# 使用左连接合并数据
airline_ontime = pd.merge(airline_ontime, on_time_flights, on='航空公司/航班号', how='left')

# 处理没有准点航班的情况
airline_ontime['准点航班数'] = airline_ontime['准点航班数'].fillna(0)

# 计算准点率
airline_ontime['准点率'] = (airline_ontime['准点航班数'] / airline_ontime['总航班数']) * 100

# 提取航空公司名称
df['航空公司'] = df['航空公司/航班号'].apply(lambda x: x.split('/')[0])

# 按航空公司汇总准点率
airline_data = airline_ontime.copy()
airline_data['航空公司'] = airline_data['航空公司/航班号'].apply(lambda x: x.split('/')[0])
airline_summary = airline_data.groupby('航空公司').agg({
    '总航班数': 'sum',
    '准点航班数': 'sum'
}).reset_index()
airline_summary['准点率'] = (airline_summary['准点航班数'] / airline_summary['总航班数']) * 100

# 绘制柱状图
plt.figure(figsize=(8, 5))
plt.bar(airline_summary['航空公司'], airline_summary['准点率'], 
        color=['#1f77b4', '#ff7f0e'], width=0.6)
plt.ylabel('准点率 (%)', fontsize=12)
plt.title('航空公司航班准点率对比', fontsize=14, fontweight='bold')

# 添加数值标签
for i, rate in enumerate(airline_summary['准点率']):
    plt.text(i, rate, f'{rate:.1f}%', ha='center', va='bottom')
plt.xticks(rotation=45, ha='right', fontsize=10)
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.tight_layout()
plt.show()

这段代码实现了航空公司准点率的计算和可视化:

  1. 数据处理阶段:

    • 按航班号分组计算总航班数
    • 筛选状态为"正常"的航班,计算准点航班数
    • 合并总航班数和准点航班数数据
    • 处理缺失值(没有准点航班的情况)
    • 计算准点率(准点航班数/总航班数×100%)
    • 从"航空公司/航班号"字段中提取航空公司名称
    • 按航空公司汇总数据,计算各航空公司的总体准点率
  2. 可视化阶段:

    • 创建柱状图,X轴为航空公司,Y轴为准点率
    • 添加数值标签显示具体准点率
    • 设置坐标轴标签、标题和网格线
    • 调整X轴标签角度,避免重叠
    • 优化布局,确保所有元素清晰显示

运行结果如下:
在这里插入图片描述

5.2 机型分布饼图

import matplotlib.pyplot as plt

# 统计各机型数量
aircraft_counts = df['机型'].value_counts()

# 绘制饼图
plt.figure(figsize=(8, 6))
wedges, texts, autotexts = plt.pie(
    aircraft_counts.values,
    labels=aircraft_counts.index,
    autopct='%1.1f%%',  # 显示百分比
    colors=['#1f77b4', '#ff7f0e', '#2ca02c'],
    textprops={'fontsize': 12},
)
plt.title('机型分布占比', fontsize=14, fontweight='bold')
plt.axis('equal')  # 保证饼图为正圆形
plt.legend(wedges, aircraft_counts.index, loc='best', fontsize=12)
plt.tight_layout()
plt.show()

这段代码展示了不同机型的分布情况:

  1. df['机型'].value_counts():统计每种机型出现的次数
  2. plt.pie():绘制饼图,包含以下关键参数:
    • autopct='%1.1f%%':显示百分比,保留一位小数
    • colors:指定饼图各部分的颜色
    • textprops:设置文本属性
  3. plt.axis('equal'):确保饼图是正圆形而非椭圆形
  4. 添加图例和标题,使图表更易理解

运行结果如下:
在这里插入图片描述

5.3 起飞时间分布折线图

import plotly.express as px

# 将计划起飞时间和实际起飞时间转换为 datetime 类型
df['计划起飞时间'] = pd.to_datetime(df['计划起飞'])
df['实际起飞时间'] = pd.to_datetime(df['实际起飞'])

# 方案一:使用向量化操作(推荐)
df['计划时间间隔'] = df['计划起飞时间'].dt.hour * 60 + df['计划起飞时间'].dt.minute // 15 * 15
df['实际时间间隔'] = df['实际起飞时间'].dt.hour * 60 + df['实际起飞时间'].dt.minute // 15 * 15

# 统计各时间间隔的航班数量
planned_counts = df['计划时间间隔'].value_counts().sort_index()
actual_counts = df['实际时间间隔'].value_counts().sort_index()

# 合并计划和实际数据
time_intervals = pd.concat([planned_counts, actual_counts], axis=1).fillna(0)
time_intervals.columns = ['计划起飞数', '实际起飞数']

# 将时间间隔转换为 HH:MM 格式
time_intervals.index = time_intervals.index.map(lambda x: f'{int(x//60)}:{int(x%60):02d}')

# 绘制折线图
fig = px.line(
    time_intervals,
    x=time_intervals.index,
    y=['计划起飞数', '实际起飞数'],
    title='起飞时间分布对比',
    labels={'value': '航班数量', 'variable': '类型'},
    markers=True,
    color_discrete_map={'计划起飞数': '#1f77b4', '实际起飞数': '#ff7f0e'}
)

# 设置x轴标签倾斜
fig.update_layout(
    xaxis=dict(tickangle=45),
    font=dict(size=12),
    title_font=dict(size=14, weight='bold')
)

fig.show()

这段代码使用 Plotly 绘制了计划起飞时间与实际起飞时间的分布对比:

  1. 数据预处理:

    • 将字符串类型的时间转换为 datetime 类型
    • 将时间按 15 分钟间隔分组(如 0:00-0:15、0:15-0:30 等)
    • 统计每个时间间隔内的计划起飞和实际起飞航班数量
    • 将分钟数格式转换为 HH:MM 格式,便于阅读
  2. 可视化:

    • 使用 Plotly Express 绘制折线图,对比计划与实际起飞分布
    • 添加标记点(markers=True)使数据点更清晰
    • 自定义颜色区分不同数据系列
    • 设置标题、标签和字体样式
    • 调整X轴标签角度,避免重叠

Plotly 生成的图表是交互式的,用户可以放大、缩小、悬停查看具体数值,增强了数据探索能力。
运行结果如下:
在这里插入图片描述

5.4 出发地-到达地流向图

import plotly.graph_objects as go

# 统计出发地到到达地的航班数量
flow_data = df.groupby(['出发地', '到达地']).size().reset_index(name='航班数')

# 构建节点和链接数据
nodes = list(set(flow_data['出发地'].tolist() + flow_data['到达地'].tolist()))
node_indices = {node: i for i, node in enumerate(nodes)}

links = []
for _, row in flow_data.iterrows():
    source = node_indices[row['出发地']]
    target = node_indices[row['到达地']]
    value = row['航班数']
    links.append({'source': source, 'target': target, 'value': value})

# 绘制桑基图
fig = go.Figure(data=[go.Sankey(
    node=dict(
        pad=15,
        thickness=20,
        line=dict(color='black', width=0.5),
        label=nodes,
        color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728']
    ),
    link=dict(
        source=[link['source'] for link in links],
        target=[link['target'] for link in links],
        value=[link['value'] for link in links],
        color=['rgba(31, 119, 180, 0.5)', 'rgba(255, 127, 14, 0.5)', 'rgba(44, 160, 36, 0.5)']
    )
)])

fig.update_layout(
    title='航班出发地-到达地流向图',
    title_font=dict(size=14, weight='bold'),
    font=dict(size=12)
)

# 保存为图片和 HTML
fig.write_image("flight_sankey.png")  # 保存为 PNG
fig.write_html("flight_sankey.html")  # 保存为交互式 HTML

这段代码使用桑基图(Sankey diagram)展示了航班的流向分布:

  1. 数据处理:

    • 按出发地和到达地分组,统计航班数量
    • 提取所有独特的城市作为节点
    • 为每个城市分配一个索引,用于构建链接关系
    • 创建链接列表,包含源节点、目标节点和流量值
  2. 桑基图绘制:

    • node 参数:定义节点样式,包括间距、厚度、边框、标签和颜色
    • link 参数:定义链接样式,包括源、目标、流量值和颜色
    • 设置图表标题和字体样式
    • 保存图表为静态图片和交互式 HTML 文件

桑基图特别适合展示流量分布,能直观地反映不同城市之间的航班流量大小,帮助我们识别主要航线。

运行结果如下:
在这里插入图片描述

六、总结

本文详细解析了一个完整的航班数据爬取与可视化分析流程,涵盖了从数据获取到存储再到多维度可视化的全过程。通过这段代码,我们可以:

  1. 自动爬取指定日期范围内的航班数据
  2. 将数据持久化存储到 MongoDB 数据库
  3. 通过多种可视化方式分析航班准点率、机型分布、起飞时间分布和航线流向

这个流程不仅适用于航班数据,也可以作为其他类型数据爬取与分析的参考框架。在实际应用中,你可以根据需要调整爬取参数、优化数据处理逻辑或增加更多的可视化维度,以获取更深入的 insights。

需要注意的是,在进行网络爬虫时,应遵守目标网站的 robots 协议,合理控制爬取频率,避免给服务器带来过大负担,确保数据获取的合法性和道德性。

七、获取完整代码

关注微信公众号:

公众号名称:数海船长
公众号ID:SeaDataCap

输入关键词“机场爬虫”即可获取完整代码下载链接

在这里插入图片描述

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值