1分鐘爬取全國高校信息,制成大屏可視化!
數(shù)據(jù)爬取
地址:https://www.gaokao.cn/school/140
F12 打開開發(fā)者工具,通過抓包工具很輕松就獲取到了 json 文件。
我們直接對該鏈接發(fā)起請求,就可以獲取對應大學的信息。
另外對比發(fā)現(xiàn) https://static-data.eol.cn/www/2.0/school/140/info.json,關鍵參數(shù) 140 為學校ID,但ID不是連續(xù)的,所以,我們爬取時只能根據(jù)大致的學校數(shù)量進行爬取。
爬取代碼
導入模塊
import?aiohttp
import?asyncio
import?pandas?as?pd
from?pathlib?import?Path
from?tqdm?import?tqdm
import?time
簡單說明一下主要模塊的用途:
aiohttp:可以實現(xiàn)單線程并發(fā) IO 操作。如果僅用在客戶端,發(fā)揮的威力不大,只是為了搭配 asyncio來使用,因為requests不支持異步。如果把asyncio用在服務器端,例如 ?Web 服務器,由于 HTTP 連接就是 IO 操作,因此可以用 單線程 +coroutine實現(xiàn)多用戶的高并發(fā)支持。asyncio:提供了完善的異步IO支持,可以將多個協(xié)程( coroutine)封裝成一組Task然后并發(fā)執(zhí)行。pandas:將爬取的數(shù)據(jù)轉(zhuǎn)為 DataFrame類型,并生成csv文件。pathlib:面向?qū)ο蟮木幊谭绞絹肀硎疚募到y(tǒng)路徑。 tqdm:只需使用 tqdm(iterable)包裝任何可迭代對象,就能讓你的循環(huán)生成一個智能進度條。
生成URL序列
通過指定的 URL 模板與 max_id 生成 URL 序列,這里添加了一個去重操作,如果之前已采集過高校信息,它會根據(jù)同目錄下的文件,剔除已采集的高校ID,僅采集未獲取過的高校信息。
def?get_url_list(max_id):
????url?=?'https://static-data.eol.cn/www/2.0/school/%d/info.json'
????not_crawled?=?set(range(max_id))
????if?Path.exists(Path(current_path,?'college_info.csv')):
????????df?=?pd.read_csv(Path(current_path,?'college_info.csv'))
????????not_crawled?-=?set(df['學校id'].unique())
????return?[url%id?for?id?in?not_crawled]
采集JSON數(shù)據(jù)
通過協(xié)程對URL序列發(fā)出請求,注意要限制并發(fā)量,Window:500,Linux:1024。
async?def?get_json_data(url,?semaphore):
????async?with?semaphore:
????????headers?=?{
????????????'User-Agent':?'Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/87.0.4280.88?Safari/537.36',
????????}
????????async?with?aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False),?trust_env=True)?as?session:
????????????try:
????????????????async?with?session.get(url=url,?headers=headers,?timeout=6)?as?response:
????????????????????#?更改相應數(shù)據(jù)的編碼格式
????????????????????response.encoding?=?'utf-8'
????????????????????#?遇到IO請求掛起當前任務,等IO操作完成執(zhí)行之后的代碼,當協(xié)程掛起時,事件循環(huán)可以去執(zhí)行其他任務。
????????????????????json_data?=?await?response.json()
????????????????????if?json_data?!=?'':
????????????????????????return?save_to_csv(json_data['data'])
????????????except:
????????????????return?None
數(shù)據(jù)解析保存
JSON數(shù)據(jù)中的字段有很多,大家可以根據(jù)自己的情況解析保存自己需要的字段。
def?save_to_csv(json_info):
????save_info?=?{}
????save_info['學校id']?=?json_info['school_id']??????????????#?學校id
????save_info['學校名稱']?=?json_info['name']??????????????????#?學校名字
????level?=?""
????if?json_info['f985']?==?'1'?and?json_info['f211']?==?'1':
????????level?+=?"985?211"
????elif?json_info['f211']?==?'1':
????????level?+=?"211"
????else:
????????level?+=?json_info['level_name']
????save_info['學校層次']?=?level???????????????????????????????#?學校層次
????save_info['軟科排名']?=?json_info['rank']['ruanke_rank']????#?軟科排名
????save_info['校友會排名']?=?json_info['rank']['xyh_rank']?????#?校友會排名
????save_info['武書連排名']?=?json_info['rank']['wsl_rank']?????#?武書連排名
????save_info['QS世界排名']?=?json_info['rank']['qs_world']?????#?QS世界排名
????save_info['US世界排名']?=?json_info['rank']['us_rank']??????#?US世界排名
????save_info['學校類型']?=?json_info['type_name']??????????????#?學校類型
????save_info['省份']?=?json_info['province_name']??????????????#?省份
????save_info['城市']?=?json_info['city_name']??????????????????#?城市名稱
????save_info['所處地區(qū)']?=?json_info['town_name']??????????????#?所處地區(qū)
????save_info['招生辦電話']?=?json_info['phone']????????????????#?招生辦電話
????save_info['招生辦官網(wǎng)']?=?json_info['site']?????????????????#?招生辦官網(wǎng)
????df?=?pd.DataFrame(save_info,?index=[0])
????header?=?False?if?Path.exists(Path(current_path,?'college_info.csv'))?else?True
????df.to_csv(Path(current_path,?'college_info.csv'),?index=False,?mode='a',?header=header)
調(diào)度程序
調(diào)度整個采集程序。獲取URL>>限制并發(fā)量>>創(chuàng)建任務對象>>掛起任務
async?def?main(loop):
????#?獲取url列表
????url_list?=??get_url_list(5000)
????#?限制并發(fā)量
????semaphore?=?asyncio.Semaphore(500)
????#?創(chuàng)建任務對象并添加到任務列表中
????tasks?=?[loop.create_task(get_json_data(url,?semaphore))?for?url?in?url_list]
????#?掛起任務列表
????for?t?in?tqdm(asyncio.as_completed(tasks),?total=len(tasks)):
????????await?t
以上就是程序運行的主要代碼。
運行效果
這里采集ID在5000以內(nèi)的高校信息,如果要盡可能多的采集高校信息的話,建議多次運行,直至無新增數(shù)據(jù)。
第一次運行(采集到2140行)
第二次運行(采集到680行)
通過兩次運行共采集到2820行數(shù)據(jù)。下面我們開始可視化部分。
Tableau可視化
相比于其他的可視化工具或者第三方繪圖庫,我更傾向于 Tableau,上手十分簡單,想要了解的可以看一下 Tableau Public,這里發(fā)布了很多大牛的作品。
https://public.tableau.com/app/discover
它唯一的缺點就是收費,如果是學生的話,可以免費使用,否則,建議先用免費版的 Tableau Public,等到充分了解后再考慮付費。
對于本次的可視化,總共繪制有四個圖表。
高校數(shù)量分布地圖

高校數(shù)量排名前三的分別是江蘇、廣東、河南(僅供參考)
軟科高校排名TOP10
根據(jù)軟科排名來看,全國TOP10的高校絕大多數(shù)都是綜合類,理工類的只有第七名的中國科學技術大學。
高校層次分布
從采集的數(shù)據(jù)中來看, 211 的高校占比本科院校約 9.5% ,985 的高校占比本科院校約 3.5%,果然是鳳毛麟角。
高校類型分布
學校類型主要還是理工類和綜合類,二者數(shù)量基本持平,都遙遙領先于其他的類型。數(shù)量第二層級為財經(jīng)類,師范類,醫(yī)藥類。
合成看板
將上述的工作表合并成一個看板,過程十分簡單,只需要將圖標拖拽到指定位置即可。
再添加一個篩選操作,點擊地圖中的某個省份聯(lián)動其他工作表。
看板已發(fā)布到 Tableau Public??梢栽诰€編輯,或下載整個可視化工作包,鏈接如下:https://public.tableau.com/shared/ZCXWTK6SP?:display_count=n&:origin=viz_share_link
完整代碼見附件:
全國高校信息采集源碼。鏈接:https://pan.baidu.com/s/1FCXwAyeeqkoH6M_ITWWAcw提取碼:6cbf
對比Excel系列圖書累積銷量達15w冊,讓你輕松掌握數(shù)據(jù)分析技能,可以在全網(wǎng)搜索書名進行了解:

