本來想參照:https://mp.weixin.qq.com/s/e7Wd7aEatcLFGgJUDkg-EQ搞一個往年編程語言動態圖的,奈何找不到數據,有數據來源的歡迎在評論區留言。
這裏找到了一個,是2020年6月的編程語言排行,供大家看一下:https://www.tiobe.com/tiobe-index/
我們要實現的效果是:
大學排名來源:http://www.zuihaodaxue.com/ARWU2003.html
部分截圖:
在http://www.zuihaodaxue.com/ARWU2003.html中的年份可以選擇,我們解析的頁面就有了:
"http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
初步獲取頁面的html信息的代碼:
def get_one_page(year):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
}
url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
response=requests.get(url,headers=headers)
if response.status_code == 200:
return response.content
except RequestException:
print('爬取失敗')
我們在頁面上進行檢查:
數據是存儲在表格中的,這樣我們就可以利用pandas獲取html中的數據,基本語法:
tb = pd.read_html(url)[num]
其中的num是標識網頁中的第幾個表格,這裏只有一個表格,所以標識為0。初步的解析代碼就有了:
def parse_on_page(html,i):
tb=pd.read_html(html)[0]
return tb
我們還要將爬取下來的數據存儲到csv文件中,基本代碼如下:
def save_csv(tb):
start_time=time.time()
tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
endtime = time.time()-start_time
print('程序運行了%.2f秒' %endtime)
最後是一個主函數,別忘了還有需要導入的包:
import requests
from requests.exceptions import RequestException
import pandas as pd
import time
def main(year):
for i in range(2003,year):
html=get_one_page(i)
tb=parse_on_page(html,i)
#print(tb)
save_csv(tb)
if __name__ == "__main__":
main(2004)
運行之後,我們在同級目錄下就可以看到university.csv,部分內容如下:
存在幾個問題:
(1)缺少年份
(2)最後一列沒有用
(3)國家由於是圖片表示,沒有爬取下來
(4)排名100以後的是一個區間
我們接下來一一解決:
(1)刪掉沒用的列
def parse_on_page(html,i):
tb=pd.read_html(html)[0]
# 重命名表格列,不需要的列用數字錶示
tb.columns = ['world rank','university', 2, 'score',4]
tb.drop([2,4],axis=1,inplace=True)
return tb
新的結果:
(2) 對100以後的進行唯一化,增加一列index作為排名標識
tb['index_rank'] = tb.index
tb['index_rank'] = tb['index_rank'].astype(int) + 1
(3)新增加年份
tb['year'] = i
(4)新增加國家
首先我們進行檢查:
發現國家在td->a>img下的圖像路徑中有名字:UnitedStates。 我們可以取出src屬性,並用正則匹配名字即可。
def get_country(html):
soup = BeautifulSoup(html,'lxml')
countries = soup.select('td > a > img')
lst = []
for i in countries:
src = i['src']
pattern = re.compile('flag.*\/(.*?).png')
country = re.findall(pattern,src)[0]
lst.append(country)
return lst
然後這麼使用:
# read_html沒有爬取country,需定義函數單獨爬取
tb['country'] = get_country(html)
最終解析的整體函數如下:
def parse_on_page(html,i):
tb=pd.read_html(html)[0]
# 重命名表格列,不需要的列用數字錶示
tb.columns = ['world rank','university', 2, 'score',4]
tb.drop([2,4],axis=1,inplace=True)
tb['index_rank'] = tb.index
tb['index_rank'] = tb['index_rank'].astype(int) + 1
tb['year'] = i
# read_html沒有爬取country,需定義函數單獨爬取
tb['country'] = get_country(html)
return tb
運行之後:
最後我們要提取屬於中國部分的相關信息:
首先將年份改一下,獲取到2019年為止的信息:
if __name__ == "__main__":
main(2019)
然後我們提取到中國高校的信息,直接看代碼理解:
def analysis():
df = pd.read_csv('university.csv')
# 包含港澳台
# 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']]
# 只包括內地
df = df.query("(country == 'China')")
df['index_rank_score'] = df['index_rank']
# 將index_rank列轉為整形
df['index_rank'] = df['index_rank'].astype(int)
# 美國
# df = df.query("(country == 'UnitedStates')|(country == 'USA')")
#求topn名
def topn(df):
top = df.sort_values(['year','index_rank'],ascending = True)
return top[:20].reset_index()
df = df.groupby(by =['year']).apply(topn)
# 更改列順序
df = df[['university','index_rank_score','index_rank','year']]
# 重命名列
df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
# 輸出結果
df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
# index可以設置
本來是想爬取從2003年到2019年的,運行時發現從2005年開始,頁面不一樣了,多了一列:
方便起見,我們就只從2005年開始了,還需要修改一下代碼:
# 重命名表格列,不需要的列用數字錶示
tb.columns = ['world rank','university', 2,3, 'score',5]
tb.drop([2,3,5],axis=1,inplace=True)
最後是整體代碼:
import requests
from requests.exceptions import RequestException
import pandas as pd
import time
from bs4 import BeautifulSoup
import re
def get_one_page(year):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
}
url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
response=requests.get(url,headers=headers)
if response.status_code == 200:
return response.content
except RequestException:
print('爬取失敗')
def parse_on_page(html,i):
tb=pd.read_html(html)[0]
# 重命名表格列,不需要的列用數字錶示
tb.columns = ['world rank','university', 2,3, 'score',5]
tb.drop([2,3,5],axis=1,inplace=True)
tb['index_rank'] = tb.index
tb['index_rank'] = tb['index_rank'].astype(int) + 1
tb['year'] = i
# read_html沒有爬取country,需定義函數單獨爬取
tb['country'] = get_country(html)
return tb
def save_csv(tb):
start_time=time.time()
tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
endtime = time.time()-start_time
print('程序運行了%.2f秒' %endtime)
# 提取國家名稱
def get_country(html):
soup = BeautifulSoup(html,'lxml')
countries = soup.select('td > a > img')
lst = []
for i in countries:
src = i['src']
pattern = re.compile('flag.*\/(.*?).png')
country = re.findall(pattern,src)[0]
lst.append(country)
return lst
def analysis():
df = pd.read_csv('university.csv')
# 包含港澳台
# 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']]
# 只包括內地
df = df.query("(country == 'China')")
df['index_rank_score'] = df['index_rank']
# 將index_rank列轉為整形
df['index_rank'] = df['index_rank'].astype(int)
# 美國
# df = df.query("(country == 'UnitedStates')|(country == 'USA')")
#求topn名
def topn(df):
top = df.sort_values(['year','index_rank'],ascending = True)
return top[:20].reset_index()
df = df.groupby(by =['year']).apply(topn)
# 更改列順序
df = df[['university','index_rank_score','index_rank','year']]
# 重命名列
df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
# 輸出結果
df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
# index可以設置
def main(year):
for i in range(2005,year):
html=get_one_page(i)
tb=parse_on_page(html,i)
save_csv(tb)
print(i,'年排名提取完成完成')
analysis()
if __name__ == "__main__":
main(2019)
運行之後會有一個university_ranking.csv,部分內容如下:
接下來就是可視化過程了。
1、 首先,到作者的github主頁:
https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js
2、克隆倉庫文件,使用git
# 克隆項目倉庫
git clone https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js
# 切換到項目根目錄
cd Historical-ranking-data-visualization-based-on-d3.js
# 安裝依賴
npm install
這裏如果git clone超時可參考:
https://www.cnblogs.com/xiximayou/p/12305209.html
需要注意的是,這裏的npm是我之前裝node.js裝了的,沒有的自己需要裝一下。
在執行npm install時會報錯:
先執行:
npm init
之後一直回車即可:
再執行npm install
任意瀏覽器打開bargraph.html
網頁,點擊選擇文件,然後選擇前面輸出的university_ranking.csv
文件,看下效果:
只能製作動圖上傳了。
可以看到,有了大致的可視化效果,但還存在很多瑕疵,比如:表順序顛倒了、字體不合適、配色太花哨等。可不可以修改呢?
當然是可以的,只需要分別修改文件夾中這幾個文件的參數就可以了:
-
config.js 全局設置各項功能的開關,比如配色、字體、文字名稱、反轉圖表等等功能;
-
color.css 修改柱形圖的配色;
-
stylesheet.css 具體修改配色、字體、文字名稱等的css樣式;
-
visual.js 更進一步的修改,比如圖表的透明度等。
知道在哪裡修改了以後,那麼,如何修改呢?很簡單,只需要簡單的幾步就可以實現:
這裏我主要修改的是config.js的以下項:
// 倒序,使得最短的條位於最上方
reverse: true,
// 附加信息內容。
// left label
itemLabel: "本年度第一大學",
// right label
typeLabel: "世界排名",
//為了避免名稱重疊
item_x: 500,
// 時間標籤坐標。建議x:1000 y:-50開始嘗試,默認位置為x:null,y:null
dateLabel_x: 1000,
dateLabel_y: -50,
最終效果:
至此,就全部完成了。
看起來簡單,還是得要自己動手才行。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準