20秒纵览中国大学学术排行榜变化

403 阅读7分钟

最近小笨聪在 B 站看到一个展示各国 GDP 排名变化的超燃视频,当看到中国赶超至世界第一时,那种自豪感油然而生!掘金不能上传视频,大家可以看原文。

微信公众号原文链接


在感叹的同时,小笨聪也很好奇这类可视化图表是怎么制作的?便找到了作者 Jannchie见齐的 B 站主页:space.bilibili.com/1850091/cha…

点进去发现还有大量此类有趣酷炫的视频。


嗯,俺也想学!

那他是怎么实现的呢?原来他用到了一个动态图形显示数据的 JavaScript 库:D3.js。那么,如果不会 D3.js 是不是就做不出来了呢?当然不是,Jannchie非常 nice 地给出了一个手把手简单教程:
见齐 手把手教程

最主要的,他还开放了程序源码,只需要做2步就能够实现:


  • 打开文件夹里面的exampe.csv文件,放进你想要展示的数据,再用浏览器打开bargraph.html网页,就可以实现动态效果。只不过要注意使用的数据格式要求。

下面是小笨聪的实例运用。首先爬取大学排行榜的数据并做处理,然后利用源码将数据可视化。


1.大学排行榜数据爬取

(1)数据来源

世界上最权威的大学排名有4类,分别是:

这里,我们选取相对比较权威也比较符合国情的第一个 ARWU 的排名结果。打开官网,可以看到有从2003年到2018的英文版和中文版排名,这里选取中文版。

确定好数据来源,然后就可以把数据爬取下来啦。

(2)分析URL获取内容

网页的URL 还是很简单的,随着年份变化而变化,我们抓取十年的数据,只需在 main 里构造一下 for 循环,url 格式如代码里所示。另外,需要注意,不同年份网页采用的编码不同,返回 response.test 会乱码,返回response.content 则不会。

 1 def get_one_page(year):
 2    try:
 3        headers = {
 4                'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
 5        }
 6        # 英文版
 7        # url = 'http://www.shanghairanking.com/ARWU%s.html' % (str(year))
 8        # 中文版
 9        url = 'http://www.zuihaodaxue.com/ARWU%s.html' % (str(year))
10        response = requests.get(url,headers = headers)
11        # 2009-2015用'gbk',2016-2018用'utf-8'
12        if response.status_code == 200:
13            return response.content
14        return None
15    except RequestException:
16        print('爬取失败')

(3)解析表格

使用read_html 函数抓取表格,并对表格进行必要处理。

 1 def parse_one_page(html,i):
 2    tb = pd.read_html(html)[0]
 3    # 重命名表格列,不需要的列用数字表示
 4    tb.columns = ['world rank','university', 2,3, 'score',4]
 5    tb.drop([2,3],axis = 1,inplace = True)
 6
 7    # rank列100名后是区间,需唯一化,增加一列index作为排名
 8    tb['index_rank'] = tb.index
 9    tb['index_rank'] = tb['index_rank'].astype(int) + 1
10    # 增加一列年份列
11    tb['year'] = i
12    # read_html没有爬取country,需定义函数单独爬取
13    tb['country'] = get_country(html)
14    print(tb) # 测试表格ok
15    return tb
16    print(tb.info()) # 查看表信息

此时的表格数据并不完整,因为没有将国家抓取下来。国家在网页里使用图片表示的,因为我们可以定位到国家代码位置。

可以看到美国是用英文的USA表示的,那么我们可以单独提取出src属性,然后用正则提取出国家名称就可以了。

 1 def get_country(html):
 2    soup = BeautifulSoup(html,'lxml')
 3    countries = soup.select('td > a > img')
 4    lst = []
 5    for i in countries:
 6        src = i['src']
 7        pattern = re.compile('flag.*\/(.*?).png')
 8        country = re.findall(pattern,src)[0]
 9        lst.append(country)
10    return lst


 world rank    university  score     ...       index_rank  year      country
0            1          哈佛大学  100.0     ...                1  2018          USA
1            2         斯坦福大学   75.6     ...                2  2018          USA
2            3          剑桥大学   71.8     ...                3  2018           UK
3            4        麻省理工学院   69.9     ...                4  2018          USA
4            5      加州大学-伯克利   68.3     ...                5  2018          USA
5            6        普林斯顿大学   61.0     ...                6  2018          USA
6            7          牛津大学   60.0     ...                7  2018           UK
7            8        哥伦比亚大学   58.2     ...                8  2018          USA
8            9        加州理工学院   57.4     ...                9  2018          USA
9           10         芝加哥大学   55.5     ...               10  2018          USA
10          11      加州大学-洛杉矶   51.2     ...               11  2018          USA
11          12         康奈尔大学   50.7     ...               12  2018          USA
12          12          耶鲁大学   50.7     ...               13  2018          USA
13          14     华盛顿大学-西雅图   50.0     ...               14  2018          USA
14          15     加州大学-圣地亚哥   47.8     ...               15  2018          USA
15          16       宾夕法尼亚大学   46.4     ...               16  2018          USA
16          17        伦敦大学学院   46.1     ...               17  2018           UK
17          18      约翰霍普金斯大学   45.4     ...               18  2018          USA
18          19     苏黎世联邦理工学院   43.9     ...               19  2018  Switzerland
19          20    华盛顿大学-圣路易斯   42.1     ...               20  2018          USA
20          21      加州大学-旧金山   41.9     ...               21  2018          USA
21          22          东京大学   41.5     ...               22  2018        Japan
22          23         多伦多大学   40.9     ...               23  2018       Canada
23          24        伦敦帝国学院   40.1     ...               24  2018           UK
24          25    西北大学(埃文斯顿)   39.9     ...               25  2018          USA
25          26          杜克大学   39.7     ...               26  2018          USA
26          27     密歇根大学-安娜堡   39.4     ...               27  2018          USA
27          28    威斯康星大学-麦迪逊   38.9     ...               28  2018          USA
28          29        哥本哈根大学   38.7     ...               29  2018      Denmark
29          30        洛克菲勒大学   37.9     ...               30  2018          USA

(4)数据处理

将前面生成的 university.csv 文件进一步处理。另外,这次的代码不仅可以获得内地大学排名,还可以列出含港澳台的排名和美国大学的排名。小笨聪也定义了一个 topn 函数,能够按年份分别求出各年的前20名大学名单。

 1def analysis():
 2    df = pd.read_csv('university.csv')
 3    # 内地
 4    df = df.query("(country == 'China')")[['university','year','index_rank']]
 5
 6    df['index_rank_score'] = df['index_rank']
 7    # 将index_rank列转为整形
 8    df['index_rank'] = df['index_rank'].astype(int)
 9    # 含港澳台
10    # df = df.query("(country == 'China')|(country == 'China-hk')|(country == 'China-tw')|
      # (country == 'China-HongKong')|(country == 'China-Taiwan')|(country == 'Taiwan,China')|(country == 'HongKong,China')")[['university','year','index_rank']]
11    # 美国
12    # df = df.query("(country == 'UnitedStates')|(country == 'USA')")[['university','year','index_rank']]
13    #求topn名
14    def topn(df):
15        top = df.sort_values(['year','index_rank'],ascending = True)
16        return top[:20].reset_index()
17    df = df.groupby(by =['year']).apply(topn)
18    # 更改列顺序
19    df = df[['university','index_rank_score','index_rank','year']]
20    # 重命名列
21    df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
22    # 输出结果
23    df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)

获取的表格数据效果如下:

2.数据可视化

首先到 见奇 的 Github 主页下载源码,然后将 bargraph.html 拖拽到浏览器,点击 选择文件,将刚才下载好的 university_ranking.csv 文件选中,即可看到动态数据图表。

不过还是有一些需要完善,比如字体大小、柱形颜色、数据项位置、图表反转等等,这些参数在源码的文件里均可以修改。当然,比较方便的办法是可以先在该网页的 css 样式表里改,改好后再到源码里修改。

源码有四个方便修改参数的文件:

  • config.js : 配置各功能的开关,比如配色、字体、是否反转图表等等;
  • color_ranges.js : 修改柱形图的颜色;
  • stylesheet.css : 具体修改配色、字体、文字名称等的 css 样式;
  • visual.js :更进一步修改,比如图表透明度。

当然,如果你比较懒,我已经帮你修改好啦(其实也并不是很容易修改...)。

微信公众号原文链接

以上就是本次爬取大学排行榜数据并制作动态图标的分析过程。

微信公众号“学编程的金融客”后台回复“大学排行榜”即可获取源码。