章鱼哥9999头像
【实战】Python爬取全国考研数据与可视化(附源码)封面图

【实战】Python爬取全国考研数据与可视化(附源码)

【实战】Python爬取全国考研数据与可视化(附源码)

很多考研同学都会关注院校招生人数、专业分数线等信息,手动整理效率极低。本篇用 Python 完成接口爬虫 + 数据存储 + 可视化分析全流程实战,从考研网站抓取院校专业数据,再通过图表直观分析数据,适合爬虫、数据分析入门学习。

一、项目的环境准备

pip install requests pandas pyecharts

二、整体开发思路

整个项目分为两大模块:数据爬虫和数据可视化。

  1. 爬虫模块:通过三层接口请求,依次获取院校、专业、分数线,最终保存为 CSV 文件;
  2. 可视化模块:读取 CSV 数据、清洗数据,使用 pyecharts 绘制多类图表并整合展示。

第一部分:数据爬取(分段拆解)

爬虫采用三层 POST 接口请求,下面按功能拆分模块,逐个讲解。

1.1 导入依赖 + 初始化全局变量

先导入需要的库,并定义列表用来存放最终爬取的数据。

import random
import requests
import time
import pandas

# 定义一个空列表,装整体数据
add_data = []

1.2 配置请求头(模拟浏览器,防拦截)

网站接口会校验访问来源,配置请求头伪装成正常浏览器访问。

# 请求头
h = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
    "referer": "https://www.kaoyan.cn/"
}

1.3 第一层请求:获取北京地区院校列表

调用接口拿到院校名称、学校唯一 ID,province_id=11 代表北京市。

# 院校接口地址与请求参数
school_api = "https://api.kaoyan.cn/pc/school/schoolList"
school_params = {
    "page": 1, "limit": 20, "province_id": "11",
    "type": "", "feature": "", "school_name": ""
}

# 发送POST请求,解析返回的JSON数据
res_school = requests.post(school_api, headers=headers, data=school_params)
school_list = res_school.json()["data"]["data"]

1.4 遍历院校 + 第二层请求:获取院校专业信息

循环每一所学校,根据学校 ID 调用接口,获取该学校下所有专业信息。

# 遍历每一所学校
for school in school_list:
    school_name = school["school_name"]
    school_id = school["school_id"]
    print(f"正在爬取:{school_name}")

    # 专业接口 + 请求参数
    major_api = "https://api.kaoyan.cn/pc/school/planListV2"
    major_params = {"limit": 5, "school_id": school_id}

    # 请求专业数据
    res_major = requests.post(major_api, headers=headers, data=major_params)
    major_list = res_major.json()["data"]["data"]

1.5 遍历专业 + 第三层请求:查询专业分数线

循环每个专业,根据专业 ID 查询分数线,增加异常捕获处理无分数的情况。承接上一段循环,在内部继续编写:

# 遍历当前学校下的所有专业
    for major in major_list:
        major_name = major["special_name"]
        recruit_num = major["recruit_number"]
        study_type = major["recruit_type_name"]
        depart = major["depart_name"]
        plan_id = major["plan_id"]

        # 分数线接口 + 参数
        score_api = "https://api.kaoyan.cn/pc/school/planDetailV2"
        score_params = {"is_apply": 2, "plan_id": plan_id}

        # 请求分数线数据
        res_score = requests.post(score_api, headers=headers, data=score_params)

        # 异常捕获:部分专业暂无分数线,避免程序报错崩溃
        try:
            min_score = res_score.json()["data"]["min_score"]
        except:
            min_score = "暂无"

1.6 数据组装 + 延时防反爬

把单条数据整理成字典存入列表,设置随机休眠,降低请求频率。

        # 组装单条完整数据
        row = {
            "学校": school_name,
            "专业": major_name,
            "院系": depart,
            "招生数": recruit_num,
            "学习方式": study_type,
            "分数线": min_score
        }
        all_data.append(row)

        # 随机延时 1~3 秒,简单规避反爬
        time.sleep(random.randint(1, 3))

1.7 数据本地持久化:保存为 CSV 文件

所有数据爬取完成后,使用 pandas 导出为本地表格文件。

# 转为DataFrame并保存CSV
df = pd.DataFrame(all_data)
df.to_csv("mnt/北京考研数据.csv", index=False, encoding="utf-8-sig")
print("数据爬取完成,已保存!")

爬虫的完整代码

import random
import requests
import time
import pandas

# 定义请求网址:发送3次请求
# 定义一个空列表。来装每个学校的专业数据
alldata = []

# 1.第一个请求网址  以北京城市的大学数据为例子
xxurl = "https://api.kaoyan.cn/pc/school/schoolList"

# 请求头
h = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
    "referer": "https://www.kaoyan.cn/"
}

# 传递的信息
xxdata = {
    "page": 1,
    "limit": 20,
    "province_id": "11",
    "type": "",
    "feature": "",
    "school_name": ""
}

# 发请求  post请求单独传递的参数,复制给data
xxres = requests.post(url=xxurl, headers=h, data=xxdata)
xxlist = xxres.json()["data"]["data"]  # 直接调用json()

'''
需要从学校信息里面获取每个学校名称和唯一id值,
'''
for xx in xxlist:
    xname = xx["school_name"]
    print(f"开始爬取{xname}的专业")
    xid = xx["school_id"]

    # 携带这个id向该学校的详情页发请求,获取对应学校专业
    zyurl = "https://api.kaoyan.cn/pc/school/planListV2"

    # 专业需要携带的请求,发请求
    zydata = {"limit": 5, "school_id": xid}  # 带上每个学校不同的id号,获取对应的专业

    # 获取专业发请求 第二次请求:
    zyres = requests.post(url=zyurl, headers=h, data=zydata)

    '''
    需要从专业信息里面提取什么,和下一步关联是什么?
    专业,招生数,学习方式,院系
    '''
    zylist = zyres.json()["data"]["data"]

    # 循环每一个专业,提取四个内容,找分数线的关键数据
    for zy in zylist:
        zyname = zy["special_name"]
        num = zy["recruit_number"]
        stype = zy["recruit_type_name"]
        departName = zy["depart_name"]

        # 从当前每个专业数据里面获取对应专业唯一的id,携带id发送第三次请求,拿到每个专业的分数线
        pid = zy["plan_id"]

        '''
        准备发第三次请求,携带专业id,拿分数线
        '''
        fsurl = "https://api.kaoyan.cn/pc/school/planDetailV2"

        # 准备传递的数据
        fsdata = {"is_apply": 2, "plan_id": pid}

        # 发请求
        fsres = requests.post(url=fsurl, headers=h, data=fsdata)

        # 获取专业分数。某些专业没有分数数据,找不到会报错,程序崩溃。try捕获报错
        try:
            score = fsres.json()["data"]["min_score"]
        except Exception as e:
            print(f"该专业暂无分数{e}")
            score = "暂无"

        # 整合数据,6个内容
        info = {
            "学校": xname,
            "专业": zyname,
            "院系": departName,
            "招生数": num,
            "学习方式": stype,
            "分数线": score,
        }
        alldata.append(info)

        # 加一个等待时间,避免短时间爬取太快
        time.sleep(random.randint(1, 3))

# 存为本地的csv数据  用pandas转数据为表格数据类型
df = pandas.DataFrame(alldata)
df.to_csv("北京考研数据.csv", index=False)
print("保存成功")

第二部分:数据可视化

读取上面生成的 CSV 数据,做数据清洗 + 多图表绘制,依旧按功能拆分代码。

2.1 导入可视化相关库

import pandas as pd
from pyecharts.charts import Page, Bar, Line
from pyecharts import options as opts

2.2 读取数据 + 数据清洗

过滤无效数据,筛选出 985 院校、全日制的有效数据,并转换字段类型。

# 读取本地CSV文件
df = pd.read_csv("mnt/全国考研数据.csv")

# 数据清洗:过滤无效值、筛选目标数据
df_clean = df[df["招生人数"] != "--"]
df_clean = df_clean[df_clean["学习方式"] == "全日制"]
df_clean = df_clean[df_clean["985"] == "是"]
df_clean["招生人数"] = df_clean["招生人数"].astype(int)

2.3 模块一:绘制专业招生人数 TOP15 柱状图

统计热门专业招生总数,取前 15 名绘制柱状图,并优化 X 轴文字展示。

# 分组统计各专业招生总人数,倒序取前15
top15_major = df_clean.groupby("专业")["招生人数"].sum()\
                      .sort_values(ascending=False).head(15)\
                      .reset_index(name="招生总人数")

# 创建柱状图对象
bar1 = Bar()
bar1.add_xaxis(top15_major["专业"].tolist())
bar1.add_yaxis("专业招生总人数", top15_major["招生总人数"].tolist(), color="red")

# 配置X轴:文字倾斜、完整展示名称
bar1.set_global_opts(
    xaxis_opts=opts.AxisOpts(axislabel_opts={"interval": 0, "rotate": 30})
)

2.4 模块二:筛选金融专业数据

单独提取金融专业数据,按学校分组,统计招生数与最低分数线。

# 筛选金融专业所有数据
df_finance = df_clean[df_clean["专业"] == "金融"]

# 按学校分组,聚合计算招生总数、最低分数线
finance_school = df_finance.groupby("学校名称").agg(
    总招生数=("招生人数", "sum"),
    最低分数=("分数线", "min")
).reset_index().sort_values("最低分数").head(10)

2.5 模块三:绘制分数线折线图

基于上一步处理好的数据,绘制院校分数线折线图。

# 创建折线图
line = Line()
line.add_xaxis(finance_school["学校名称"].tolist())
line.add_yaxis(
    "最低分数线",
    finance_school["最低分数"].tolist(),
    linestyle_opts=opts.LineStyleOpts(color="#E53E3E")
)

# X轴样式优化
line.set_global_opts(
    xaxis_opts=opts.AxisOpts(axislabel_opts={"interval": 0, "rotate": 30})
)

2.6 模块四:绘制招生人数柱状图 + 图表叠加

绘制金融专业招生人数柱状图,并将折线图叠加在柱状图上,实现组合图表。

# 创建柱状图(招生人数)
bar2 = Bar()
bar2.add_xaxis(finance_school["学校名称"].tolist())
bar2.add_yaxis("金融专业招生数", finance_school["总招生数"].tolist(), color="data")
bar2.set_global_opts(
    xaxis_opts=opts.AxisOpts(axislabel_opts={"interval": 0, "rotate": 30})
)

# 折线图叠加到柱状图中
bar2.overlap(line)

2.7 模块五:整合所有图表,生成 HTML 文件

使用 Page 容器把多张图表放在同一个页面,最终渲染出网页文件。

# 创建页面容器
page = Page(layout=Page.SimplePageLayout)

# 加入所有图表
page.add(bar1, bar2)

# 渲染为本地HTML,浏览器可直接打开
page.render("考研数据可视化.html")
print("图表绘制完成!")

完整数据可视化代码

# 从绘图的库中引入柱状图和折线图
from pyecharts.charts import Page, Bar, Line  # 需要安装:pip install pyecharts
from pyecharts import options as opts
import pandas

# 读取、清除脏数据、过滤需要的数据
dfData = pandas.read_csv("全国考研数据.csv")

# 招生人数清洗
newdf = dfData[dfData["招生人数"] != "--"]
newdf = newdf[newdf["学习方式"] == "全日制"]
newdf = newdf[newdf["985"] == "是"]

# 转换类型
newdf["招生人数"] = newdf["招生人数"].astype(int)

# 分组统计不同专业的招生数,从高到低取前15个
zydata = newdf.groupby("专业")["招生人数"].sum().sort_values(
    ascending=False
).head(15).reset_index(name="招生总人数")

# 创建柱状图
bar = Bar()
x_data = zydata["专业"].tolist()
y_data = zydata["招生总人数"].tolist()
bar.add_xaxis(x_data)
bar.add_yaxis("各专业招生总数", y_data, color="red")

# 优化X轴,让名称完整显示并倾斜30度
bar.set_global_opts(
    xaxis_opts=opts.AxisOpts(
        axislabel_opts={
            "interval": 0,
            "rotate": 30
        }
    )
)

# 查看金融专业的招生情况
major = newdf[newdf["专业"] == "金融"]

# 按学校聚合招生总数与最低分数
majorschool = major.groupby("学校名称").agg(
    总招生数=("招生人数", "sum"),
    最低分数=("分数线", "min")
).reset_index()

# 按最低分数排序,取前10个
resultdata = majorschool.sort_values(
    by="最低分数", ascending=True
).head(10)

# 绘制各学校金融专业分数线对比折线图
x_data = resultdata["学校名称"].tolist()
y_data = resultdata["最低分数"].tolist()
line = Line()
line.add_xaxis(x_data)
line.add_yaxis(
    "各学校金融专业分数线",
    y_data,
    z_level=2,
    linestyle_opts=opts.LineStyleOpts(color="#E53E3E")
)
line.set_global_opts(
    xaxis_opts=opts.AxisOpts(
        axislabel_opts={
            "interval": 0,
            "rotate": 30
        }
    )
)

# 绘制各学校金融专业招生人数对比柱状图
y2_data = resultdata["总招生数"].tolist()
bar2 = Bar()
bar2.add_xaxis(x_data)
bar2.add_yaxis("金融专业招生总数对比", y2_data, color="data")
bar2.set_global_opts(
    xaxis_opts=opts.AxisOpts(
        axislabel_opts={
            "interval": 0,
            "rotate": 30
        }
    )
)

# 把折线图合并到柱状图中
bar2.overlap(line)

# 创建装所有图表的容器
page = Page(layout=Page.SimplePageLayout)

# 把三个图表整合在一个页面里
page.add(bar, line, bar2)

# 渲染合成的图表
page.render("考研数据可视化.html")
print("绘制结束")

三、项目总结

  1. 爬虫部分:采用接口直爬方式,分三层请求数据,搭配请求头、延时、异常捕获应对基础反爬,最终落地为 CSV 表格;

  2. 可视化部分:先清洗脏数据,再分别绘制柱状图、折线图,支持图表叠加与多图合并,可视化结果直观易懂;

  3. 拓展方向:修改省份 ID 爬取全国数据、增加分页逻辑、新增饼图 / 散点图丰富分析维度。

本期内容就分享到这里啦!如果你在实践过程中遇到任何问题,或者想获取文中提到的完整源码、
配置文件模板,以及更多进阶玩法,可扫码领取(无套路,纯分享)。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/KKKKK666658/article/details/167920848

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--