Li Shen Blog

Stay hungry, stay foolish.

Python爬取2021软科世界大学排名【2021.12.01】

沈大力

——写在前面——

软科排名是四大世界大学排行榜之一(其他三个是QS,TIMES,US News),相比于QS和TIMES,软科排名更侧重于评估学校的学术水平。因此,对于想出国读博/做博后/找学术职位的人来说,该排名可以作为选校时的一个重要参考指标。但软科排名有一个很大的缺点,就是如果某个学校不是世界前100,那么该学校的排名直接显示为范围(如101-150,201-300)。并且该范围内所有大学按照首字母的顺序排列,如Arizona State University已经连续几年排在101-150这个区间的第一名。软科自己的说法是某一范围内的这些大学水平都差不多(大概这么个意思)。不过话虽如此,软科给这些学校各个部分的打分却仍然有较明显的差别。根据软科自己的算法,我们完全可以对各部分的分数*权重后求和算出每个学校的总分,然后给他重新排个名。个人认为这样的排名才会更有意义一些。

 

——数据获取——

想要重新计算排名,首先就得获取数据,最简单的方法就是用python爬他们网站了。不过他们网站今年彻底重做了一次,导致我去年写的脚本已经完全失效了。因此只能重写代码。仔细看了看他们网站,发现两个问题:1. 每个页面只显示30所大学,且没有选项可以让整个页面显示所有大学;2. 翻页采用的是ajax(用的nuxt.js框架),也就是说翻页的时候网站url不会改变,那么也就无法通过暴力遍历所有page的url来爬取数据。我想了想,大致整理了两条思路,第一条是用selenium模拟人为操作获取数据,第二条就是看看有没有api可以用。先试了试第一条思路, 虽然能跑,但代码量稍微大了点。我就想:如果通过API的方式来提取数据,会不会更简洁高效一些?于是我百度了下相关的博文,试图找相关的API,结果看到这个博主分享了一个软科搞的中国大学排名的api(python爬虫小案例_中国大学排名(2021.04.11))。参考这个api,我就用chrome的开发者工具去世界大学排名页面的sources中的js文件中找所有的api字眼,结果真就找到了两个可用的api:

1. https://www.shanghairanking.com/api/pub/v1/arwu/rank?version=<year>
2. https://www.shanghairanking.com/api/pub/v1/inst/<univUp>

第一个api返回的数据含有你在排名页面看到的所有数据,每个大学对应的json数据结构如下:

{"ranking":"1","univNameEn":"Harvard University","univUp":"harvard-university","univLogo":"logo/032bd1b77.png","region":"United States","regionLogo":"us","regionRanking":"1","score":100,"indData":{"140":100,"141":100,"142":100,"143":100,"144":80.5,"145":100}}

其中,“ranking”是世界排名;“univNameEn”是学校名称;“univUp”可以理解为学校ID,结合第二个api使用可获取该学校的详细信息;“univLogo”是学校logo图片;“region”是地区;“regionLogo”是国旗;“regionRanking”是地区排名;“score”是总得分;“indData”是各项指标得分的集合,140是校友获奖得分(Alumini),141是教师获奖得分(Award),142是高被引科学家得分(HiCi),143是NS论文得分(N&S),144是师均表现(PCP),145是国际论文得分(PUB)。知晓了以上信息后,我们就把问题转变为了从json文件中提取数据。那就简单了:

 

import requests
import json

url='https://www.shanghairanking.com/api/pub/v1/arwu/rank?version=2021'

def get_url(url):
    headers = {
        'User-Agent':'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
        'Referer':'https://shanghairanking.com/',
        'DNT':'1',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Connection':'keep-alive',
        'Accept-Language':'zh-CN,zh;q=0.9,en-CN;q=0.8,en;q=0.7',
        'Accept-Encoding':'gzip, deflate',
    }
    req = requests.get(url, headers=headers)
    req.encoding='utf-8'
    html = req.json()
    return html

dataset = get_url(url)['data']['rankings']
idx = len(dataset)

f = open('arwu_2021.txt', 'w', encoding='utf-8')
f.write('World-Rank' + '\t' + 'Name' + '\t' + 'Region' + '\t' + 'Alumini' + '\t' + 'Award' + '\t' + 'HiCi' + '\t' + 'N&S' + '\t' + 'PCP' + '\t' + 'PUB' + '\t' + 'Total' + '\n')
for i in range(idx):
    WorldRank = dataset[i]['ranking']
    UniName = dataset[i]['univNameEn']
    Region = dataset[i]['region']
    Alumini = dataset[i]['indData']['140']
    Award = dataset[i]['indData']['141']
    HiCi = dataset[i]['indData']['142']
    NS = dataset[i]['indData']['143']
    PCP = dataset[i]['indData']['144']
    PUB = dataset[i]['indData']['145']
    Total = dataset[i]['score']
    summary = str(WorldRank) + '\t' + str(UniName) + '\t' + str(Region) + '\t' + str(Alumini) + '\t' + str(Award) + '\t' + str(HiCi) + '\t' + str(NS) + '\t' + str(PCP) + '\t' + str(PUB) + '\t' + str(Total) + '\n'
    f.write(summary)
f.close()

 

数据爬下来后,可以直接弄到excel里面算总分,至于权重比例可参考官网的排名方法。当然,如果你懒得爬我这边也整理好了一份,可自行下载

72人读过
工具/方法/算法 Python
Dec. 1, 2021, 1:46 p.m.

评论:

登录后方可评论,点击登录注册

评论列表:

暂无评论。

苏公网安备 32050602011302号

苏ICP备2020062135号-1
Copyright© Li Shen. All rights reserved.