【实战】Python爬取全国考研数据与可视化(附源码)
很多考研同学都会关注院校招生人数、专业分数线等信息,手动整理效率极低。本篇用 Python 完成接口爬虫 + 数据存储 + 可视化分析全流程实战,从考研网站抓取院校专业数据,再通过图表直观分析数据,适合爬虫、数据分析入门学习。
一、项目的环境准备
pip install requests pandas pyecharts
二、整体开发思路
整个项目分为两大模块:数据爬虫和数据可视化。
- 爬虫模块:通过三层接口请求,依次获取院校、专业、分数线,最终保存为 CSV 文件;
- 可视化模块:读取 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("绘制结束")
三、项目总结
-
爬虫部分:采用接口直爬方式,分三层请求数据,搭配请求头、延时、异常捕获应对基础反爬,最终落地为 CSV 表格;
-
可视化部分:先清洗脏数据,再分别绘制柱状图、折线图,支持图表叠加与多图合并,可视化结果直观易懂;
-
拓展方向:修改省份 ID 爬取全国数据、增加分页逻辑、新增饼图 / 散点图丰富分析维度。
本期内容就分享到这里啦!如果你在实践过程中遇到任何问题,或者想获取文中提到的完整源码、
配置文件模板,以及更多进阶玩法,可扫码领取(无套路,纯分享)。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/KKKKK666658/article/details/167920848




