Python:使用爬虫获取中国最好的大学排名数据(爬虫入门)
文章目錄
- 問(wèn)題描述
- 結(jié)果展示
- 解決思路
- 代碼實(shí)現(xiàn)
- 代碼講解
- 總結(jié)一下
- 使用 XPath 實(shí)現(xiàn)
問(wèn)題描述
請(qǐng)使用 Python 爬取最好大學(xué)網(wǎng)的 大學(xué)排名數(shù)據(jù) ,并保存為 CSV 和 Excel 格式。
結(jié)果展示
以爬取前 10 名大學(xué)為例:
解決思路
目標(biāo)網(wǎng)站:軟科中國(guó)最好大學(xué)排名2019
使用 Python 的 BeautifulSoup 庫(kù):BeautifulSoup官方文檔
這里主要使用了 BeautifulSoup 庫(kù),該庫(kù)功能十分強(qiáng)大,我只使用了它不到 1% 的功能。更多的功能請(qǐng)大家看官方文檔,是中文的哦。
因?yàn)槭鞘褂门老x(chóng),所以必須引入的兩個(gè)庫(kù)是:requests 和 BeautifulSoup,另外設(shè)計(jì)存儲(chǔ)到 Excel 中,所以我選擇使用 pandas 庫(kù),它的二維結(jié)構(gòu)提供很方便的方法可以直接存儲(chǔ)到 Excel 中,另外用到pandas就會(huì)用到numpy用來(lái)生成二維數(shù)組。
所以用到的庫(kù)有:
- 🔥 requests
- 🔥 bs4
- 🔥 pandas
- 🔥 numpy
代碼實(shí)現(xiàn)
import requests as rq from bs4 import BeautifulSoup as Bs import pandas as pd import numpy as npdef getData(resLoc):rp = rq.get(resLoc)rp.encoding = 'utf-8'return rp.textdef dataProcessing(html, num):table = Bs(html, features='lxml').table.find_all('tr', limit=num, recursive=True)table_head = table[0]universityList = []for tr in table[1:]:tds = tr.find_all('td')contents = [td.contents for td in tds]contents[1] = contents[1][0].contentsuniversityList.append(contents)thf = [th.contents for th in table_head.find_all('th', limit=4)]for i in [op.contents for op in table_head.find_all('option', recursive=True)]:thf.append(i)thf = ["".join(th) for th in thf]univList = []for university in universityList:university = ["".join(attr) for attr in university]univList.append(university)return pd.DataFrame(np.array(univList), columns=thf)def saveData(data):data.to_csv('university.csv', index=False)data.to_excel('university.xlsx', index=False)def main(num):if num >= 549:returnelse:url = 'http://zuihaodaxue.com/zuihaodaxuepaiming2019.html'saveData(dataProcessing(getData(url), num + 1))# 測(cè)試,爬取前 10 名大學(xué)的信息 main(10)但是,相信大家看了上面的代碼肯定想殺人,這代碼的可讀性幾乎為0,根本不是寫(xiě)給人看的,所以下面我們講解一下代碼。
代碼講解
下面我采用注釋的方式帶大家一步一步的來(lái)解決這個(gè)問(wèn)題,并且可以學(xué)到很多知識(shí)。
首先我們先導(dǎo)包:
import requests as rq from bs4 import BeautifulSoup as Bs import pandas as pd import numpy as np我們使用的 BeautifulSoup 是 bs4 中的一個(gè)類,所以我們引入該類就可以了,順便起一個(gè)別名。
但是這個(gè)庫(kù)實(shí)際上是叫做 beautifulsoup的,我們 install 的時(shí)候也是安裝的 beautifulsoup ,但是執(zhí)行的導(dǎo)包的時(shí)候是 bs4。
這里我們以一種自頂向下的思維編程,具體就是,先列出函數(shù),函數(shù)具體怎么執(zhí)行的我先不管,我只要你的返回值,然后我拿來(lái)使用。
所以我們先在 main 方法中定義一些函數(shù),之后再實(shí)現(xiàn)。
def main(num):# 由于該網(wǎng)站最多有550個(gè)大學(xué),所以輸入的數(shù)字不能大于550,否則什么也不做if num >= 550:print("數(shù)量不能大于550")returnelse:url = 'http://zuihaodaxue.com/zuihaodaxuepaiming2019.html'# 獲取數(shù)據(jù)text = getData(url)# 處理數(shù)據(jù), num 是你要爬取前多少名大學(xué)的排名信息universityList = dataProcessing(text, num + 1)# 保存數(shù)據(jù)saveData(universityList)print("文件保存成功!")我們打開(kāi)這個(gè)網(wǎng)站來(lái)看一下:
習(xí)慣上我們使用 F12 打開(kāi),也可以右鍵表格,點(diǎn)擊檢查:
我們需要的數(shù)據(jù)就在這里面:
每一個(gè) tr 里面都有一行數(shù)據(jù),這就是我們想要的,而表頭就是標(biāo)題,我們后面都會(huì)用到。
現(xiàn)在我們一個(gè)一個(gè)的實(shí)現(xiàn)這些函數(shù):
首先是 getData(url) 方法,該方法就是通過(guò)程序獲取我們?cè)跒g覽器看到的 Html 頁(yè)面。
# 獲取數(shù)據(jù),就是通過(guò)訪問(wèn)網(wǎng)頁(yè),把他的html源代碼拿過(guò)來(lái) def getData(resLoc):rp = rq.get(resLoc)rp.encoding = 'utf-8'return rp.textget 表示是 GET 請(qǐng)求,encoding 設(shè)置編碼。
好了,獲取了數(shù)據(jù),我們就要分割處理數(shù)據(jù)了。
就是 dataProcessing(html, num) 方法,num 是爬取的大學(xué)數(shù)量。
首先創(chuàng)建一個(gè) BeautifulSoup 對(duì)象:
bs = Bs(html, features='lxml')然后呢,這個(gè) bs 其實(shí)代表是整個(gè) HTML 的 DOM 樹(shù),我們要做的就是從這個(gè) DOM 樹(shù)中取東西。
我們之前已經(jīng)看過(guò) HTML 的格式了,他只有一個(gè) table 標(biāo)簽,所以我們可以通過(guò)點(diǎn)的方式獲取這個(gè) table 元素。
然后他返回的還是一個(gè) bs 對(duì)象,只不過(guò)這個(gè) DOM 樹(shù)變小了,所以我們可以使用 find_all 方法來(lái)獲取 table 下的所有 tr標(biāo)簽。
# 包含表頭的列表 table = bs.table.find_all('tr', limit=num, recursive=True)但是這里是有問(wèn)題的,因?yàn)檫@張表有表頭,表頭的 tr我們需要單獨(dú)拿出來(lái)。
我們打印出來(lái)看一下表頭是啥:
# 看一下表頭是什么:# <tr># <th style="text-align: center;">排名</th># <th style="text-align: center;">學(xué)校名稱</th># <th class="hidden-xs" style="text-align: center; width: 80px;">省市</th># <th style="text-align: center;">總分</th># <th class="hidden-xs" style="text-align: center; width: 265px;">指標(biāo)得分<br/># <select class="form-control" id="select-indicator-type" name="type" style="text-align: left;"># <option selected="selected" title="生源質(zhì)量(新生高考成績(jī)得分)" value="indicator5">生源質(zhì)量(新生高考成績(jī)得分)</option># <option title="培養(yǎng)結(jié)果(畢業(yè)生就業(yè)率)" value="indicator6">培養(yǎng)結(jié)果(畢業(yè)生就業(yè)率)</option># <option title="社會(huì)聲譽(yù)(社會(huì)捐贈(zèng)收入·千元)" value="indicator7">社會(huì)聲譽(yù)(社會(huì)捐贈(zèng)收入·千元)</option># <option title="科研規(guī)模(論文數(shù)量·篇)" value="indicator8">科研規(guī)模(論文數(shù)量·篇)</option># <option title="科研質(zhì)量(論文質(zhì)量·FWCI)" value="indicator9">科研質(zhì)量(論文質(zhì)量·FWCI)</option># <option title="頂尖成果(高被引論文·篇)" value="indicator10">頂尖成果(高被引論文·篇)</option># <option title="頂尖人才(高被引學(xué)者·人)" value="indicator11">頂尖人才(高被引學(xué)者·人)</option># <option title="科技服務(wù)(企業(yè)科研經(jīng)費(fèi)·千元)" value="indicator12">科技服務(wù)(企業(yè)科研經(jīng)費(fèi)·千元)</option># <option title="成果轉(zhuǎn)化(技術(shù)轉(zhuǎn)讓收入·千元)" value="indicator13">成果轉(zhuǎn)化(技術(shù)轉(zhuǎn)讓收入·千元)</option># <option title="學(xué)生國(guó)際化(留學(xué)生比例) " value="indicator14">學(xué)生國(guó)際化(留學(xué)生比例)</option># </select># </th># </tr>這正是我們想要的數(shù)據(jù),我們可以通過(guò) contents 獲取 標(biāo)簽對(duì) 里面的數(shù)據(jù),就大功告成了。
# 這里為什么只要四個(gè)呢? 因?yàn)榈谖鍌€(gè)是下拉選框,我們后面再單獨(dú)處理 ths = table_head.find_all('th', limit=4) # 這里是表頭的前四個(gè)元素 [['排名'], ['學(xué)校名稱'], ['省市'], ['總分']], th_four 代表前四個(gè)th thf = [th.contents for th in ths]在仔細(xì)看你會(huì)發(fā)現(xiàn)后面有一個(gè)不是普通的列表,他是一個(gè) select!所以我們上面只要了前四個(gè)。
下面處理下拉框中的元素 option;
打印出來(lái)看看:
# [ ['生源質(zhì)量(新生高考成績(jī)得分)'],# ['培養(yǎng)結(jié)果(畢業(yè)生就業(yè)率)'],# ['社會(huì)聲譽(yù)(社會(huì)捐贈(zèng)收入·千元)'],# ['科研規(guī)模(論文數(shù)量·篇)'],# ['科研質(zhì)量(論文質(zhì)量·FWCI)'],# ['頂尖成果(高被引論文·篇)'],# ['頂尖人才(高被引學(xué)者·人)'],# ['科技服務(wù)(企業(yè)科研經(jīng)費(fèi)·千元)'],# ['成果轉(zhuǎn)化(技術(shù)轉(zhuǎn)讓收入·千元)'],# ['學(xué)生國(guó)際化(留學(xué)生比例)'] ]正是我們想要的,不過(guò)他是二維列表,不怕后面我們?cè)偬幚怼?/p>
將這個(gè)和之前的 4 個(gè)合并。
for i in options:thf.append(i)現(xiàn)在我們處理表體,也就是最最干貨的內(nèi)容。
# 去掉表頭,只要表體 table_body = table[1:]打印出來(lái)看一下每一條 tr 里面是什么?
# [ <tr class="alt"># <td>1</td> --排名# <td><div align="left">清華大學(xué)</div></td> --學(xué)校名稱# <td>北京</td> --省市# <td>94.6</td> --總分# <td class="hidden-xs need-hidden indicator5">100.0</td> --生源質(zhì)量# <td class="hidden-xs need-hidden indicator6" style="display: none;">98.30%</td> --培養(yǎng)結(jié)果# <td class="hidden-xs need-hidden indicator7" style="display: none;">1589319</td> --社會(huì)聲譽(yù)# <td class="hidden-xs need-hidden indicator8" style="display: none;">48698</td> --科研規(guī)模# <td class="hidden-xs need-hidden indicator9" style="display: none;">1.512</td> --科研質(zhì)量# <td class="hidden-xs need-hidden indicator10" style="display: none;">1810</td> --頂尖成果# <td class="hidden-xs need-hidden indicator11" style="display: none;">126</td> --頂尖人才# <td class="hidden-xs need-hidden indicator12" style="display: none;">1697330</td> --科技服務(wù)# <td class="hidden-xs need-hidden indicator13" style="display: none;">302898</td> --成果轉(zhuǎn)化# <td class="hidden-xs need-hidden indicator14" style="display: none;">6.81%</td> --學(xué)生國(guó)際化# </tr> ]我們可以無(wú)視上面標(biāo)簽中的屬性值,只關(guān)注內(nèi)容,也就是說(shuō)對(duì)于table_body中的每一個(gè)tr標(biāo)簽,我們要做的是取出來(lái)其中的td中的content,作為二維列表。
編寫(xiě)一個(gè)循環(huán)來(lái)遍歷每一個(gè) tr:
universityList = [] for tr in table_body:tds = tr.find_all('td')這個(gè)時(shí)候我們打印一下tds看看:
# tds 的結(jié)果是:# print(tds)# [ <td>1</td>,# <td><div align="left">清華大學(xué)</div></td>,# <td>北京</td>, <td>94.6</td>,# <td class="hidden-xs need-hidden indicator5">100.0</td>,# <td class="hidden-xs need-hidden indicator6" style="display: none;">98.30%</td>,# <td class="hidden-xs need-hidden indicator7" style="display: none;">1589319</td>,# <td class="hidden-xs need-hidden indicator8" style="display: none;">48698</td>,# <td class="hidden-xs need-hidden indicator9" style="display: none;">1.512</td>,# <td class="hidden-xs need-hidden indicator10" style="display: none;">1810</td>,# <td class="hidden-xs need-hidden indicator11" style="display: none;">126</td>,# <td class="hidden-xs need-hidden indicator12" style="display: none;">1697330</td>,# <td class="hidden-xs need-hidden indicator13" style="display: none;">302898</td>,# <td class="hidden-xs need-hidden indicator14" style="display: none;">6.81%</td> ]可以看到是一個(gè)列表,我們獲取每一個(gè) td 標(biāo)簽的 content:
contents = [td.contents for td in tds] # for td in tds:# print(td.contents)# 得到的結(jié)果如下:# ['1']# [<div align="left">清華大學(xué)</div>]# ['北京']# ['94.6']# ['100.0']# ['98.30%']# ['1589319']# ['48698']# ['1.512']# ['1810']# ['126']# ['1697330']# ['302898']# ['6.81%']但是有一個(gè)問(wèn)題就是 [<div align="left">清華大學(xué)</div>] 這里有一個(gè) div 標(biāo)簽,我們要把它替換成他里面的元素值。
contents[1] = contents[1][0].contents大家注意我們現(xiàn)在還在for循環(huán)當(dāng)中哦,我們要這些遍歷到的contents存到外面的變量中才能保存起來(lái)
universityList.append(contents)現(xiàn)在我們得到的列表就是類似于這種形式[[[清華], [1], ...], [[北大], [2], ...], ...]
降維打擊!
# 下面的問(wèn)題是, 我們有了表頭列表 thf(二維),有了表體列表 universityList(三維), 怎么把它們合并呢? # thf: [['排名'], ['學(xué)校名稱'], ['省市'], ['總分'], ['生源質(zhì)量(新生高考成績(jī)得分)'], ['培養(yǎng)結(jié)果(畢業(yè)生就業(yè)率)'], ['社會(huì)聲譽(yù)(社會(huì)捐贈(zèng)收入·千元)'], ['科研規(guī)模(論文數(shù)量·篇)'], ['科研質(zhì)量(論文質(zhì)量·FWCI)'], ['頂尖成果(高被引論文·篇)'], ['頂尖人才(高被引學(xué)者·人)'], ['科技服務(wù)(企業(yè)科研經(jīng)費(fèi)·千元)'], ['成果轉(zhuǎn)化(技術(shù)轉(zhuǎn)讓收入·千元)'], ['學(xué)生國(guó)際化(留學(xué)生比例)']] # universityList: [ # [['1'], ['清華大學(xué)'], ['北京'], ['94.6'], ['100.0'], ['98.30%'], ['1589319'], ['48698'], ['1.512'], ['1810'], ['126'], ['1697330'], ['302898'], ['6.81%']], # [['2'], ['北京大學(xué)'], ['北京'], ['76.5'], ['95.2'], ['98.07%'], ['570497'], ['47161'], ['1.409'], ['1402'], ['100'], ['554680'], ['14445'], ['6.15%']] # ]我們使用 DataFrame配合 numpy 可以實(shí)現(xiàn)這個(gè)功能,因?yàn)镈ataFrame有一個(gè)功能就是可以將幾行和一列數(shù)據(jù)一一對(duì)應(yīng)形成一個(gè)表格。
# 但是還有一個(gè)問(wèn)題就是DataFrame是二維結(jié)構(gòu),我們這里是三維結(jié)構(gòu),顯然需要降維打擊! # 我們把最里面的列表可以轉(zhuǎn)化為字符串,實(shí)現(xiàn)降維 # 降維的過(guò)程 thf = ["".join(th) for th in thf] univList = [] for university in universityList:university = ["".join(attr) for attr in university]univList.append(university)# 下面使用 DataFrame 的構(gòu)造函數(shù),傳入一個(gè) numpy 構(gòu)造的數(shù)組和一個(gè)列表作為表頭 pd_universityList = pd.DataFrame(np.array(univList), columns=thf)return pd_universityList上面的代碼值得一提的就是這一個(gè)pd.DataFrame(np.array(univList), columns=thf),這里先是傳入了一個(gè)二維數(shù)組,然后第二個(gè)參數(shù)columns指的就是表頭,也就是說(shuō)他會(huì)形成一種一一對(duì)應(yīng)的關(guān)系,columns的每一個(gè)元素,對(duì)應(yīng)二維數(shù)組的每一個(gè)元素的對(duì)應(yīng)元素。
比如說(shuō)我們的二維數(shù)組是:
1,清華大學(xué),北京 2,北京大學(xué),北京那么columns對(duì)應(yīng)的就是排名,學(xué)校名稱,省市,他會(huì)自動(dòng)將排名和1,2對(duì)應(yīng),學(xué)校和清華大學(xué)對(duì)應(yīng)。
在調(diào)試的過(guò)程中可能 DataFrame 顯示不全,可以采用下面的方法顯示全。
# 顯示所有列 # pd.set_option('display.max_columns', None) # 顯示所有行 # pd.set_option('display.max_rows', None) # 設(shè)置value的顯示長(zhǎng)度為100,默認(rèn)為50 # pd.set_option('max_colwidth', 100) # print(pd_universityList)到此為止,我們最重要的方法就介紹完了,下面我們編寫(xiě)第三個(gè)函數(shù)吧。
# 負(fù)責(zé)保存數(shù)據(jù)到本地磁盤(pán) def saveData(data):data.to_csv('university.csv', index=False)data.to_excel('university.xlsx', index=False)這里直接使用DataFrame自帶的方法就可以實(shí)現(xiàn)保存到本地。
好了,全部都做完了,下面我們只需要調(diào)用一下主函數(shù)即可運(yùn)行程序。
輸入幾就可以獲取前幾名大學(xué)的數(shù)據(jù),但是不能超過(guò)550,因?yàn)槟蔷W(wǎng)頁(yè)上就只有549個(gè) 。
# 測(cè)試,爬取前10名大學(xué)的信息 main(10)
帶注釋的代碼展示:
總結(jié)一下
最重要的還是看 文檔,我這里只用了一個(gè)方法就是find_all,他還有非常多強(qiáng)大的功能,我們只需要會(huì)使用就行了,我太 CAI 了,只是一個(gè) API 選手,你敢信就這幾行代碼我扣了倆小時(shí)才寫(xiě)出來(lái)😔,還是得更努力的學(xué),雖然學(xué)到最后還只是一個(gè) API 調(diào)用者。
會(huì)這一個(gè)方法就可以爬一些網(wǎng)站的數(shù)據(jù)了,其他的也是以此類推,只需要分析另一個(gè)網(wǎng)頁(yè)的 DOM 結(jié)構(gòu)即可,所以方法是通用的,如果你也是初學(xué),不妨使用這個(gè)項(xiàng)目練練手。
使用 XPath 實(shí)現(xiàn)
從http://www.zuihaodaxue.cn/網(wǎng)站中爬蟲(chóng)數(shù)據(jù),獲取中國(guó)大學(xué)排名(Top10)
- 爬取的數(shù)據(jù)保存為CSV文件(.CSV)
- 采用xpath語(yǔ)法提取數(shù)據(jù)
總結(jié)
以上是生活随笔為你收集整理的Python:使用爬虫获取中国最好的大学排名数据(爬虫入门)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 8.2 英文词频统计(project)
- 下一篇: 【UE4笔记】C++游戏控制的摄像机