估计很多人在填报高考自愿的时候都会难以选择学校,有自己心仪的专业,但是在网上搜了半天也不能确定填哪一所学校。如果填了录取分数线低的,那将会浪费很多分数,表示有点遗憾。如果没有录取上,那就更遗憾了… 在我们想根据专业来选择学校的时候,往往会有很多学校无法被自己根据专业搜索到,但又很适合自己,全国那么多学校,大好的机会就只能完美错过了。所以,该怎么把全国所有带有该专业的学校和往年的录取分数线一起找出来,并进行录取分数对比呢?
数据来源: 高考数据库
操作环境: win10, python3.6, jupyter notebook,谷歌浏览器(都不是必选项)
获取内容: 学校、往年的理科录取情况(最高分,平均分,最低分,最低位次, 录取批次)
实现思路:
获取高考数据库的数据接口
查询数据
技术实现讲解
1、查找高考数据库的数据接口
1.1、获取某校的高考录取情况
(1)直接搜索学校,在《XX大学高考分数线_招生信息_中国教育在线》中查看录取分数线,找到专业分数线,(也可以在官网中搜索学校),右击检查。
(2)粘贴刚才复制的链接到浏览器中看看是否存在我们需要的数据
1.2、分析其他的数据接口
我们需要的数据都在其中,但这只是一个学校的,我们要怎么查看其他学校的呢?不妨多对比一下其他学校的数据接口吧
通过对比,发现每个学校链接的id值都不同,如“贵州财经大学”的school_id=520,只需要分别传值给这个链接,就可以获取该系统所有学校的路径了,除了没有填写录取分数线的学校。除此之外,上面还有时间,从网页中可以发现它也对应了每个学校的时间,就可以根据它来查询年度。
2、查询数据
2.1、请求数据
熟悉了网页数据的结构后,就可以请求数据开始提取了,导入requests库请求数据,网页使用的是post方法请求,一定要注意请求的方法。导入time库间断请求时间,并制作请求头模拟浏览器请求数据,告诉服务器这是一个浏览器来请求数据。
import requests,time #导入库
#制作请求头
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
}
major = input("请查询输入专业:")
times = input("请输入查询年份(2014~2018):")
for i in range(32,968,1):#id 从32到967
url = f'https://api.eol.cn/gkcx/api/?access_token=&local_province_id=52&local_type_id=1&page=1&school_id={i}&signsafe=&size=20&uri=apidata/api/gk/score/special&year='+str(times)
time.sleep(0.1)
res = requests.post(url=url,headers=headers)
你可能会好奇为什么id是从32~968呢?因为并不是每个id都有数据,如id为“1”的结果为:
{"code":"0000","message":"成功","data":{"numFound":0,"item":[]},"md5":"F03C3B1E12B97478ED80E3868E2EEA94"}
通过id值测验,发现没有内容的id接口都会返回这个值
"md5":"F03C3B1E12B97478ED80E3868E2EEA94"
我们就可以通过它来过滤掉没有数据的接口,并确定id的总长度。
import requests,time
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
}
for i in range(1,1000):#预设学校id有999个,[ 1,1000)
url = f'https://api.eol.cn/gkcx/api/?access_token=&local_province_id=52&local_type_id=1&page=1&school_id={i}&signsafe=&size=20&uri=apidata/api/gk/score/special&year=2018'
time.sleep(0.1)
res = requests.post(url=url,headers=headers)
if res.json()['md5'] =='F03C3B1E12B97478ED80E3868E2EEA94':
print ("学校id",i,"不存在")
else:
print (res.json()['md5'])
运行结果:
学校id 1 不存在
学校id 2 不存在
学校id 3 不存在
...............#省略部分输出
学校id 30 不存在
学校id 31 不存在
EAA4D9DA22841248D9826B8CF6641F95
B7FD4BC855287B5788366520335B54B4
4653CF0302C731E679E5D1F765A20FE6
...............#省略部分输出
学校id 964 不存在
学校id 965 不存在
8CCBA1E84159C24BA81B3E647198F7FF
98062D0DAFF19F39CA094E714645DB6D
学校id 968 不存在
学校id 969 不存在
...............#省略后面输出
通过这样查找测试,我们就能确定学校id的长度了,同时这样也可以省下前面id的查找时间。
2.2、提取数据
我们请求到的数据是字典型,可以把其中一个学校的数据解析成格式化的json文件,便于查找。可以使用python库来解析
import pprint
pprint.pprint(res.json())
也可以在网上进行线上json解析
2.3、需要注意的坑
有些学校其他数据都有,包括分数、位次、批次等,就是没有专业。如西南科技大学
所以必需要判断"spname"是否在字典中,先满足这个条件再获取其他信息。同时,为了提高程序的运行效率,可以先判断它是否有数据再执行其他的条件。
for i in range(32,968,1):
url = f'https://api.eol.cn/gkcx/api/?access_token=&local_province_id=52&local_type_id=1&page=1&school_id={i}&signsafe=&size=20&uri=apidata/api/gk/score/special&year='+str(times)
time.sleep(0.1)#暂停0.1秒
res = requests.post(url=url,headers=headers)
if res.json()['md5'] !='F03C3B1E12B97478ED80E3868E2EEA94':#字典不为空再继续执行下面条件语句
for items in res.json()['data']['item']:
if('spname' in items):#存在spname才执行,如西南科技大学
if (items['spname'] == major):
print (items['name'],'\t',str(times)+"年"+str(major)+"录取最高分",items['max'],'\t',"平均分:",items['average'],'\t',"最低分:",items['min'],'\t',"最低位次:",items['min_section'],'\t',"录取批次:",items['local_batch_name'],'\n')
print (str(times)+"年全国"+str(major)+"专业录取信息查询完成!") #所有数据遍历完成后才会打印它
3、源代码汇总
import requests,time #导入库
#制作请求头
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
}
#未来提高代码的效率,没有对输入内容进行判断
major = input("请查询输入专业:")
times = input("请输入查询年份(2014~2018):")
for i in range(32,968,1):#学校id从[32,967),省略前面部分可以节约时间
url = f'https://api.eol.cn/gkcx/api/?access_token=&local_province_id=52&local_type_id=1&page=1&school_id={i}&signsafe=&size=20&uri=apidata/api/gk/score/special&year='+str(times)
time.sleep(0.1) #暂停时间模拟人为请求
res = requests.post(url=url,headers=headers)
if res.json()['md5'] !='F03C3B1E12B97478ED80E3868E2EEA94': #字典不为空再继续执行下面条件语句,提高效率
for items in res.json()['data']['item']:
if('spname' in items): #存在spname才执行,如西南科技大学
if (items['spname'] == major):
print (items['name'],'\t',str(times)+"年"+str(major)+"录取最高分",items['max'],'\t',"平均分:",items['average'],'\t',"最低分:",items['min'],'\t',"最低位次:",items['min_section'],'\t',"录取批次:",items['local_batch_name'],'\n')
print (str(times)+"年全国"+str(major)+"专业录取信息查询完成!") #所有数据遍历完成后才会打印它
运行代码:
查询结果:
注意:有很多学校是大类招生,如贵州财经大学的计算机相关专业叫做计算机类,到大二后才细分专业,所有这样是搜索不到的,就只能查询填报志愿时的专业。
特别提示:
上面的代码还存在一些漏洞,有很多学校的数据是分两个页面存放的,我目前还没有找到三个页面存放的。
如果我们想刷新后再取它的数据接口,它就直接跳到了第一页,第二个接口是不可能取到的,但我们可以直接赋值为page=2。
而刚才的代码就只爬取了第一个页面,上面第2个页面的信息就获取不到,现在要再遍历查询一次,时间也会相应的增加,它的关键词是专业,就算没有第二个页面,也不会乱码匹配数据的,它本身就不存在对应的专业。遍历两个页面后,就可以获取到第二个页面的值了。
爬取两页面代码汇总:
import requests,time
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
}
major = input("请查询输入专业:")
times = input("请输入查询年份(2014~2018):")
for i in range(32,968,1):
for page in range(1,3):#增加为第一个和第二个页面
url = f'https://api.eol.cn/gkcx/api/?access_token=&local_province_id=52&local_type_id=1&page={page}&school_id={i}&signsafe=&size=20&uri=apidata/api/gk/score/special&year='+str(times)
time.sleep(0.1)
res = requests.post(url=url,headers=headers)
if res.json()['md5'] !='F03C3B1E12B97478ED80E3868E2EEA94':
for items in res.json()['data']['item']:
if('spname' in items):
if (items['spname'] == major):
print (items['name'],'\t',str(times)+"年"+str(major)+"录取最高分",items['max'],'\t',"平均分:",items['average'],'\t',"最低分:",items['min'],'\t',"最低位次:",items['min_section'],'\t',"录取批次:",items['local_batch_name'],'\n')
print (str(times)+"年全国"+str(major)+"专业录取信息查询完成!")
再次提醒: 就只能查询对应的专业,大类招生后的分类专业并不能查询!!!
数据全部来自高考数据库 ,只供学习使用,如有侵权,敬请联系 ayouleyang@qq.com