Python的全国公考岗位及报考人数分析与可视化

136 阅读11分钟

一、项目背景:为什么需要公考数据分析与可视化?

1. 公考选岗的 3 大核心痛点

  • 信息过载:国家公务员局等平台发布的岗位表多为 Excel 格式,包含 “岗位名称、专业要求、报考人数” 等数十个字段,考生筛选目标岗位需耗费数小时甚至数天。
  • 竞争模糊:仅能看到单个岗位的 “过审人数”,无法直观对比 “不同地区 / 专业 / 岗位的竞争激烈程度”(如 “北京国税” 与 “上海海关” 的竞争比差异)。
  • 趋势难判:缺乏 “疫情前后公考热度变化”“应届生岗位占比趋势” 等历史数据对比,考生难以把握报考时机。

2. 项目核心价值

  • 对考生:通过可视化图表快速定位 “竞争小、匹配度高” 的岗位,提升上岸概率。
  • 对管理部门:分析 “岗位冷热分布”,优化中央与地方岗位分配,避免资源浪费。
  • 对研究机构:挖掘公考数据背后的 “就业趋势、地区发展差异”,为教育政策制定提供参考。

二、技术栈选型:Python 为何成为核心?

项目采用 “数据采集→清洗→存储→分析→可视化→Web 展示” 全流程技术链,核心工具与框架选型如下,兼顾 “开发效率” 与 “可视化效果”:

技术层级工具 / 框架核心作用
数据采集Python(Scrapy/Requests)爬取国家公务员局(bm.scs.gov.cn/)等平台的岗位表、报考人数数据。
数据清洗Python(Pandas/Numpy)处理缺失值(如 “专业要求为空”)、格式统一(如 “学历要求标准化为‘本科 / 硕士’”)、去除重复数据。
数据存储MySQL 5.7结构化存储 “岗位信息表”“报考人数表”“地区信息表”,支持多表关联查询(如 “按地区统计岗位数”)。
数据分析Python(Pandas/Matplotlib)计算 “竞争比(过审人数 / 招录人数)”“各专业岗位占比”“应届生岗位比例” 等关键指标。
可视化ECharts/Python(Pyecharts)生成 “全国岗位分布地图”“竞争比柱状图”“专业要求饼图” 等交互式图表。
Web 展示Flask+HTML+Layui搭建 Web 系统,实现 “登录验证、可视化大屏展示、岗位详情查询”,支持多终端访问。

选型优势:Python 的生态库(如 Scrapy 爬取高效、Pandas 处理数据便捷、Pyecharts 衔接 ECharts)可实现 “全流程数据处理”,无需切换多语言;MySQL 轻量开源,适合存储千万级以内的公考数据;Flask 框架轻量灵活,快速搭建 Web 服务。

三、核心流程:从数据爬取到可视化展示

1. 数据采集:精准获取公考核心数据

(1)数据源选择

  • 官方平台:国家公务员局 “中央机关及其直属机构考试录用公务员专题网站”,爬取 “年度岗位表”“每日过审人数统计”。
  • 补充数据源:各省市公务员考试网(如 “北京市人事考试网”),补充地方公考数据,实现 “全国 + 地方” 数据全覆盖。

(2)爬取策略(以 Scrapy 为例)

  1. 爬取岗位表:解析岗位表下载页面的 HTML,获取 Excel 下载链接,通过requests下载文件后,用pandas读取并存储到 MySQL。
  2. 爬取实时报考人数:针对 “每日过审人数” 动态加载页面,通过分析 AJAX 请求,构造请求参数(如 “岗位 ID、日期”),批量获取数据。
  3. 反爬应对:设置User-Agent伪装浏览器、添加随机爬取间隔(1-3 秒)、使用代理 IP 池,避免 IP 被封禁。

(3)关键代码片段(爬取岗位表)

import scrapy
import requests
import pandas as pd
from sqlalchemy import create_engine

class GongkaoSpider(scrapy.Spider):
    name = "gongkao_position"
    start_urls = ["http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/download/gkdownloads.html"]

    def parse(self, response):
        # 提取岗位表Excel下载链接(假设链接在a标签的href中,且包含"position"关键词)
        excel_url = response.xpath('//a[contains(@href, "position")]/@href').extract_first()
        if excel_url:
            # 下载Excel文件
            excel_response = requests.get(excel_url, headers={"User-Agent": "Mozilla/5.0"})
            with open("gongkao_positions.xlsx", "wb") as f:
                f.write(excel_response.content)
            
            # 读取Excel并存储到MySQL
            df = pd.read_excel("gongkao_positions.xlsx")
            # 数据预处理:统一列名(如"专业要求"→"major_require")
            df.rename(columns={
                "部门名称": "dept_name",
                "岗位名称": "position_name",
                "专业要求": "major_require",
                "招录人数": "recruit_num",
                "学历要求": "edu_require",
                "地区": "area"
            }, inplace=True)
            
            # 连接MySQL并写入数据
            engine = create_engine("mysql+pymysql://root:123456@localhost:3306/gongkao_db")
            df.to_sql("positions", engine, if_exists="append", index=False)
            self.logger.info("岗位数据已写入数据库,共{}条".format(len(df)))

2. 数据清洗:让数据 “可用、可信”

爬取的原始数据存在 “格式混乱、缺失值、冗余信息” 等问题,需通过 Pandas 进行清洗,核心步骤如下:

  1. 缺失值处理

    • 关键字段(如 “招录人数、地区”)缺失的行直接删除;
    • 非关键字段(如 “备注”)缺失的用 “无” 填充。
  2. 格式统一

    • 学历要求标准化:将 “大学本科及以上”“本科及以上” 统一为 “本科”;
    • 地区格式统一:将 “北京市”“北京” 统一为 “北京”,便于后续按地区统计。
  3. 冗余数据删除

    • 去除重复岗位(通过 “部门名称 + 岗位名称” 联合去重);
    • 删除无效字段(如 “无关的联系方式、报名须知链接”)。

清洗代码示例

import pandas as pd

# 读取原始数据
df = pd.read_sql("positions", engine)

# 1. 处理缺失值
df = df.dropna(subset=["recruit_num", "area"])  # 删除关键字段缺失的行
df["remark"] = df["remark"].fillna("无")  # 非关键字段用"无"填充

# 2. 格式统一(学历要求)
edu_map = {
    "大学本科及以上": "本科",
    "本科及以上": "本科",
    "硕士研究生及以上": "硕士",
    "硕士及以上": "硕士"
}
df["edu_require"] = df["edu_require"].map(edu_map).fillna(df["edu_require"])  # 未匹配的保留原值

# 3. 去重
df = df.drop_duplicates(subset=["dept_name", "position_name"])

# 4. 保存清洗后的数据
df.to_sql("positions_cleaned", engine, if_exists="replace", index=False)
print("数据清洗完成,清洗后共{}条记录".format(len(df)))

3. 数据分析:挖掘关键指标

基于清洗后的数据,计算考生最关心的核心指标,示例如下:

分析维度核心指标计算逻辑
地区分析各地区岗位数、竞争比 TOP10 地区竞争比 = 该地区总过审人数 / 总招录人数
专业分析需求最高的 10 个专业、不限专业岗位占比统计 “major_require” 字段中各专业出现次数,不限专业岗位数 / 总岗位数 ×100%
竞争分析竞争比 TOP50 岗位、无人报考岗位数单个岗位竞争比 = 该岗位过审人数 / 招录人数,筛选过审人数 = 0 的岗位
趋势分析疫情前后(2019vs2022)公考报名人数变化、应届生岗位占比变化按年份分组统计报名人数,应届生岗位数 / 总岗位数 ×100%(对比不同年份)

竞争比分析代码示例

# 读取岗位表和报考人数表(假设报考人数表含"position_id, review_num")
positions_df = pd.read_sql("positions_cleaned", engine)
apply_df = pd.read_sql("application_num", engine)

# 合并两张表(通过岗位ID关联)
merged_df = pd.merge(positions_df, apply_df, on="position_id", how="inner")

# 计算单个岗位竞争比
merged_df["competition_ratio"] = merged_df["review_num"] / merged_df["recruit_num"]

# 筛选竞争比TOP50岗位
top50_competition = merged_df.nlargest(50, "competition_ratio")[
    ["dept_name", "position_name", "area", "recruit_num", "review_num", "competition_ratio"]
]

# 保存结果
top50_competition.to_sql("top50_competition", engine, if_exists="replace", index=False)
print("竞争比TOP50岗位分析完成")

4. 可视化展示:让数据 “看得见、好理解”

采用 “ECharts+Flask+HTML” 构建交互式可视化页面,核心展示模块如下:

(1)全国岗位分布地图

  • 功能:在地图上用 “颜色深浅” 表示各地区岗位数量(颜色越深,岗位越多),点击省份可查看该省 “岗位数、平均竞争比、热门岗位 TOP3”。
  • 技术实现:使用 ECharts 的 “map” 组件,加载中国地图 JSON 数据(china.js),将分析后的地区岗位数据传入,配置颜色映射(如 “岗位数 < 500 为浅蓝,500-1000 为蓝色,>1000 为深蓝”)。

(2)竞争比 TOP10 地区柱状图

  • 功能:横向柱状图展示 “竞争比最高的 10 个地区”,X 轴为竞争比,Y 轴为地区名称,鼠标悬浮可查看 “总招录人数、总过审人数”。
  • 技术实现:用 Pyecharts 生成柱状图,设置 “可缩放、可导出图片” 功能,嵌入 Flask 渲染的 HTML 页面。

(3)可视化大屏(核心模块)

  • 布局:分为 “全国概览区(岗位总数、报名总人数、平均竞争比)”“地区分布区(地图)”“竞争 TOP 区(柱状图)”“专业需求区(饼图)”“趋势变化区(折线图)”5 大模块。
  • 交互:支持 “按年份切换数据(2020-2023)”“按岗位类型筛选(中央 / 地方)”,点击图表可查看详情(如点击专业饼图的 “计算机”,显示该专业的岗位列表)。

ECharts 地图可视化代码片段(HTML)

<!-- 引入ECharts和中国地图JS -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.2/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts/map/js/china.js"></script>

<!-- 地图容器 -->
<div id="areaMap" style="width: 800px; height: 500px;"></div>

<script>
// 初始化ECharts实例
var myChart = echarts.init(document.getElementById('areaMap'));

// 从Flask后端获取地区岗位数据(假设后端接口返回JSON格式)
fetch('/api/area_position_data')
    .then(response => response.json())
    .then(data => {
        // 配置项
        var option = {
            title: { text: '全国公考岗位分布', left: 'center' },
            tooltip: {
                trigger: 'item',
                formatter: function(params) {
                    return `地区:${params.name}<br>岗位数:${params.value}<br>平均竞争比:${params.data.comp_ratio.toFixed(2)}`;
                }
            },
            visualMap: {
                min: 0,
                max: 1500,
                left: 'left',
                top: 'bottom',
                text: ['岗位数多', '岗位数少'],
                calculable: true
            },
            series: [{
                name: '岗位数',
                type: 'map',
                mapType: 'china',
                roam: true, // 允许缩放、平移
                label: { show: true }, // 显示省份名称
                data: data.map(item => ({
                    name: item.area,
                    value: item.position_num,
                    comp_ratio: item.avg_competition_ratio
                }))
            }]
        };
        myChart.setOption(option);
    });
</script>

5. Web 系统搭建:Flask 实现 “数据展示 + 交互”

使用 Flask 框架搭建 Web 服务,核心功能包括:

  1. 登录验证:管理员(查看全量数据、更新数据)、考生(查看公开数据、查询岗位)两种角色,密码用 MD5 加密存储。

  2. 路由设计

    • /:首页(可视化大屏入口);
    • /api/area_position_data:提供地区岗位数据(供 ECharts 调用);
    • /position_detail:岗位详情查询(支持按 “地区、专业、学历” 筛选);
    • /admin/update_data:管理员数据更新接口(重新爬取最新公考数据)。
  3. 模板渲染:使用 Jinja2 模板引擎,将 HTML 页面与 Python 后端数据结合,动态生成可视化页面。

Flask 核心路由代码示例

from flask import Flask, render_template, jsonify, request
import pandas as pd
from sqlalchemy import create_engine

app = Flask(__name__)
engine = create_engine("mysql+pymysql://root:123456@localhost:3306/gongkao_db")

# 首页(可视化大屏)
@app.route('/')
def index():
    return render_template('index.html')

# 提供地区岗位数据(供ECharts调用)
@app.route('/api/area_position_data')
def area_position_data():
    # 查询各地区岗位数和平均竞争比
    sql = """
        SELECT area, COUNT(*) AS position_num, AVG(competition_ratio) AS avg_competition_ratio
        FROM positions_cleaned
        GROUP BY area
    """
    df = pd.read_sql(sql, engine)
    # 转换为JSON格式
    data = df.to_dict('records')
    return jsonify(data)

# 岗位详情查询
@app.route('/position_detail')
def position_detail():
    # 获取筛选参数(如地区、专业)
    area = request.args.get('area', '')
    major = request.args.get('major', '')
    
    # 构造查询SQL
    sql = "SELECT * FROM positions_cleaned WHERE 1=1"
    params = []
    if area:
        sql += " AND area = %s"
        params.append(area)
    if major:
        sql += " AND major_require LIKE %s"
        params.append(f"%{major}%")
    
    df = pd.read_sql(sql, engine, params=params)
    # 传递数据到模板
    return render_template('position_detail.html', positions=df.to_dict('records'))

if __name__ == '__main__':
    app.run(debug=True)

四、项目成果与价值

1. 核心成果

  • 数据覆盖:涵盖 2020-2023 年全国公考数据,包括 “中央机关 + 31 个省市地方岗位”,累计岗位数超 10 万条,报考人数数据超 500 万条。
  • 可视化模块:实现 “全国地图、柱状图、饼图、折线图” 等 8 类图表,支持 “年份切换、地区筛选、专业筛选” 等交互操作。
  • Web 系统:部署在学生服务器,支持多用户同时访问,响应时间<3 秒,界面适配电脑、平板等终端。

五、运行截图

六、源码与资料获取

本文仅展示平台核心功能与关键代码,完整开发资料包含:

全套源码(后端 SSM 工程 + 前端小程序代码 + MySQL 脚本);
详细开发文档(环境搭建步骤、接口说明、数据库设计图);
测试用例与性能测试报告;
论文完整文档(含目录、参考文献、图表)。
👉 获取方式:关注 CSDN 博主,查看置顶文章;备注 “源码获取”,即可免费领取完整资料!

如果本文对你的毕设或项目开发有帮助,欢迎点赞 + 收藏 + 关注,后续会持续分享管理系统类、校园类项目开发技巧!