问题描述
爬取中国大学排名网站2015-2024年的中国大学排名数据,,包含的内容有: 排名, 学校名称, 省市, 类型, 总分, 办学层次(生源质量)
问题分析
目标网站:【软科排名】2024年最新软科中国大学排名|中国最好大学排名
首先,我们先点开网页的源代码进行分析。
通过查找可以看见网页源代码是包含了前30所大学的排名信息,我们回到开始页面,通过点击发现,当我们点击下一页的时候网页的地址没有变化,这就说明了网页的信息并不是 只存在与源代码中,这时候我们就需要点击F12去开发者界面的network去查看日志
如果要对动态的网页就行抓包的话,我们一般查看XHR和JS这两个部分的信息,通过查找,我们发现XHR中没有我们想要的信息,那么就去JS中查找
我们发现JS中的payload中似乎有我们想要的信息
接下来我们就要拿去这个部分的内容尝试打印看是否是我们需要的内容,首先我们先获取网页的url和user-agent
然后进行代码的编写
import requests def daxue(): url=f'https://www.shanghairanking.cn/_nuxt/static/1722314823/rankings/bcur/202411/payload.js' headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36' } r=requests.get(url, headers=headers).content.decode() print(r) if __name__ == '__main__': daxue()
查看我们打印出来的结果
通过结果我们可以得出,除了大学名称和大学分数,其他部分的数据均被加密,这边导致我们无法获得真实的内容
在 2021 年 4 月份,有其他大佬通过 network 找到了软科排名网站返回数据的 API,具体参考python爬虫小案例_中国大学排名(2021.04.11)_中国大学排名爬虫计算第一名学校的总分与第二十名的总分相差多少。-CSDN博客
至此我们获取了网页的接口
https://www.shanghairanking.cn/api/pub/v1/bcur?bcur_type=11&year=2021
可以看出时间是2021年,但现在我们无法在日志里找到这个接口,可能是被官网给隐藏了,我们尝试一下给时间改为2024年,再进行数据的查看
这里可以看到,接口依然可以使用,并且上面有我们想要的所有信息
接着我们将其通过代码来进行拿取和分析
可以看见其中有排名, 学校名称, 省市, 类型, 总分, 办学层次(生源质量)
接下来我们进行年份的更换来查看各个字段是否发生变化,以方便我们更好的拿取数据
2023年
2022年
2021年
2020年
2019年
2018年
2017年
2016年
2015年
根据对比发现各个字段都没有变化,除了 办学层次(生源质量)
这里我用了一个笨方法直接设置了一个字典,将每年的inData里的数字部分对应了出来
dict_leve={'2015':'1','2016':'10','2017':'19','2018':'28','2019':'38','2020':'59','2021':'159','2022':'271','2023':'411','2024':'536'}
然后我们就可以设置一个循环,开始的年份为2015,然后打印一次结果后加一,直到2024年打印完毕,下面是代码
完整代码
import requests import re def daxue(): # 设置起始年份为2015 year = 2015 # 遍历从2015年到2024年的每一年 for year in range(2015, 2025): # 构造请求URL,其中年份作为参数传递 url = f'https://www.shanghairanking.cn/api/pub/v1/bcur?bcur_type=11&year={year}' # 设置请求头,模拟浏览器访问 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36' } # 发送GET请求并获取响应内容,将其解析为JSON格式 r = requests.get(url, headers=headers).json() # 提取排名数据 data = r['data']['rankings'] # 定义一个字典,存储每年的等级对应的键值 dict_leve = {'2015': '1', '2016': '10', '2017': '19', '2018': '28', '2019': '38', '2020': '59', '2021': '159', '2022': '271', '2023': '411', '2024': '536'} # 如果当前年份在字典中,则获取对应的键值 if str(year) in dict_leve: k = dict_leve[str(year)] # 遍历排名数据 for i in data: # 提取排名、学校名称、省份、类型、得分和等级等信息 rank = i['ranking'] name = i['univNameCn'] province = i['province'] type = i['univCategory'] score = i['score'] level = i['indData'][f'{k}'] # 打印提取的信息 print(rank, name, province, type, score, level) # 将提取的信息写入CSV文件 with open(f'{year}年大学排名.csv', 'a', encoding='utf-8') as f: f.write('排名,学校名称,城市,类型,得分,等级') f.write(f'{rank},{name},{province},{type},{score},{level}') # 打印完成信息 print(f"{year}年打印完毕") # 更新年份 year += 1 if __name__ == '__main__': daxue()
打印结果(部分)