我們先以一個(gè)最簡(jiǎn)單的實(shí)例來(lái)了解模擬登錄后頁(yè)面的抓取過(guò)程,其原理在于模擬登錄后 Cookies 的維護(hù)。
1. 本節(jié)目標(biāo)
本節(jié)將講解以 GitHub 為例來(lái)實(shí)現(xiàn)模擬登錄的過(guò)程,同時(shí)爬取登錄后才可以訪問(wèn)的頁(yè)面信息,如好友動(dòng)態(tài)、個(gè)人信息等內(nèi)容。
我們應(yīng)該都聽(tīng)說(shuō)過(guò) GitHub,如果在我們?cè)?Github 上關(guān)注了某些人,在登錄之后就會(huì)看到他們最近的動(dòng)態(tài)信息,比如他們最近收藏了哪個(gè) Repository,創(chuàng)建了哪個(gè)組織,推送了哪些代碼。但是退出登錄之后,我們就無(wú)法再看到這些信息。
如果希望爬取 GitHub 上所關(guān)注人的最近動(dòng)態(tài),我們就需要模擬登錄 GitHub。
2. 環(huán)境準(zhǔn)備
請(qǐng)確保已經(jīng)安裝好了 requests 和 lxml 庫(kù),如沒(méi)有安裝可以參考第 1 章的安裝說(shuō)明。
3. 分析登錄過(guò)程
首先要分析登錄的過(guò)程,需要探究后臺(tái)的登錄請(qǐng)求是怎樣發(fā)送的,登錄之后又有怎樣的處理過(guò)程。
如果已經(jīng)登錄 GitHub,先退出登錄,同時(shí)清除 Cookies。
打開(kāi) GitHub 的登錄頁(yè)面,鏈接為 https://github.com/login,輸入 GitHub 的用戶名和密碼,打開(kāi)開(kāi)發(fā)者工具,將 Preserve Log 選項(xiàng)勾選上,這表示顯示持續(xù)日志,如圖 10-1 所示。
點(diǎn)擊登錄按鈕,這時(shí)便會(huì)看到開(kāi)發(fā)者工具下方顯示了各個(gè)請(qǐng)求過(guò)程,如圖 10-2 所示。
點(diǎn)擊第一個(gè)請(qǐng)求,進(jìn)入其詳情頁(yè)面,如圖 10-3 所示。
可以看到請(qǐng)求的 URL 為 https://github.com/session,請(qǐng)求方式為 POST。再往下看,我們觀察到它的 Form Data 和 Headers 這兩部分內(nèi)容,如圖 10-4 所示。
Headers 里面包含了 Cookies、Host、Origin、Referer、User-Agent 等信息。Form Data 包含了 5 個(gè)字段,commit 是固定的字符串 Sign in,utf8 是一個(gè)勾選字符,authenticity_token 較長(zhǎng),其初步判斷是一個(gè) Base64 加密的字符串,login 是登錄的用戶名,password 是登錄的密碼。
綜上所述,我們現(xiàn)在無(wú)法直接構(gòu)造的內(nèi)容有 Cookies 和 authenticity_token。下面我們?cè)賮?lái)探尋一下這兩部分內(nèi)容如何獲取。
在登錄之前我們會(huì)訪問(wèn)到一個(gè)登錄頁(yè)面,此頁(yè)面是通過(guò) GET 形式訪問(wèn)的。輸入用戶名密碼,點(diǎn)擊登錄按鈕,瀏覽器發(fā)送這兩部分信息,也就是說(shuō) Cookies 和 authenticity_token 一定是在訪問(wèn)登錄頁(yè)的時(shí)候設(shè)置的。
這時(shí)再退出登錄,回到登錄頁(yè),同時(shí)清空 Cookies,重新訪問(wèn)登錄頁(yè),截獲發(fā)生的請(qǐng)求,如圖 10-5 所示。
訪問(wèn)登錄頁(yè)面的請(qǐng)求如圖所示,Response Headers 有一個(gè) Set-Cookie 字段。這就是設(shè)置 Cookies 的過(guò)程。
另外,我們發(fā)現(xiàn) Response Headers 沒(méi)有和 authenticity_token 相關(guān)的信息,所以可能 authenticity_token 還隱藏在其他的地方或者是計(jì)算出來(lái)的。我們?cè)購(gòu)木W(wǎng)頁(yè)的源碼探尋,搜索相關(guān)字段,發(fā)現(xiàn)源代碼里面隱藏著此信息,它是一個(gè)隱藏式表單元素,如圖 10-6 所示。
現(xiàn)在我們已經(jīng)獲取到所有信息,接下來(lái)實(shí)現(xiàn)模擬登錄。
4. 代碼實(shí)戰(zhàn)
首先我們定義一個(gè) Login 類,初始化一些變量:
1
2
3
4
5
6
7
8
9
10
11
12
|
class Login( object ): def __init__( self ): self .headers = { 'Referer' : 'https://github.com/' , 'User-Agent' : 'Mozilla / 5.0 (Windows NT 10.0 ; WOW64) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 57.0 . 2987.133 Safari / 537.36 ', 'Host' : 'github.com' } self .login_url = 'https://github.com/login' self .post_url = 'https://github.com/session' self .logined_url = 'https://github.com/settings/profile' self .session = requests.Session() |
這里最重要的一個(gè)變量就是 requests 庫(kù)的 Session,它可以幫助我們維持一個(gè)會(huì)話,而且可以自動(dòng)處理 Cookies,我們不用再去擔(dān)心 Cookies 的問(wèn)題。
接下來(lái),訪問(wèn)登錄頁(yè)面要完成兩件事:一是通過(guò)此頁(yè)面獲取初始的 Cookies,二是提取出 authenticity_token。
在這里我們實(shí)現(xiàn)一個(gè) token() 方法,如下所示:
1
2
3
4
5
6
|
from lxml import etree def token( self ): response = self .session.get( self .login_url, headers = self .headers) selector = etree.HTML(response.text) token = selector.xpath( '//div/input[2]/@value' )[ 0 ] return token |
我們用 Session 對(duì)象的 get() 方法訪問(wèn) GitHub 的登錄頁(yè)面,然后用 XPath 解析出登錄所需的 authenticity_token 信息并返回。
現(xiàn)在已經(jīng)獲取初始的 Cookies 和 authenticity_token,開(kāi)始模擬登錄,實(shí)現(xiàn)一個(gè) login() 方法,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def login( self , email, password): post_data = { 'commit' : 'Sign in' , 'utf8' : '?' , 'authenticity_token' : self .token(), 'login' : email, 'password' : password } response = self .session.post( self .post_url, data = post_data, headers = self .headers) if response.status_code = = 200 : self .dynamics(response.text) response = self .session.get( self .logined_url, headers = self .headers) if response.status_code = = 200 : self .profile(response.text) |
首先構(gòu)造一個(gè)表單,復(fù)制各個(gè)字段,其中 email 和 password 是以變量的形式傳遞。然后再用 Session 對(duì)象的 post() 方法模擬登錄即可。由于 requests 自動(dòng)處理了重定向信息,我們登錄成功后就可以直接跳轉(zhuǎn)到首頁(yè),首頁(yè)會(huì)顯示所關(guān)注人的動(dòng)態(tài)信息,得到響應(yīng)之后我們用 dynamics() 方法來(lái)對(duì)其進(jìn)行處理。接下來(lái)再用 Session 對(duì)象請(qǐng)求個(gè)人詳情頁(yè),然后用 profile() 方法來(lái)處理個(gè)人詳情頁(yè)信息。
其中,dynamics() 方法和 profile() 方法的實(shí)現(xiàn)如下所示:
1
2
3
4
5
6
7
8
9
10
11
|
def dynamics( self , html): selector = etree.HTML(html) dynamics = selector.xpath( '//div[contains(@class, "news")]//div[contains(@class, "alert")]' ) for item in dynamics: dynamic = ' ' .join(item.xpath( './/div[@class="title"]//text()' )).strip() print (dynamic) def profile( self , html): selector = etree.HTML(html) name = selector.xpath( '//input[@id="user_profile_name"]/@value' )[ 0 ] email = selector.xpath( '//select[@id="user_profile_email"]/option[@value!=""]/text()' ) print (name, email) |
在這里,我們?nèi)匀皇褂?XPath 對(duì)信息進(jìn)行提取。在 dynamics() 方法里,我們提取了所有的動(dòng)態(tài)信息,然后將其遍歷輸出。在 prifile() 方法里,我們提取了個(gè)人的昵稱和綁定的郵箱,然后將其輸出。
這樣,整個(gè)類的編寫就完成了。
5. 運(yùn)行
我們新建一個(gè) Login 對(duì)象,然后運(yùn)行程序,如下所示:
1
2
3
|
if __name__ = = "__main__" : login = Login() login.login(email = 'cqc@cuiqingcai.com' , password = 'password' ) |
在 login() 方法傳入用戶名和密碼,實(shí)現(xiàn)模擬登錄。
可以看到控制臺(tái)有類似如下輸出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
GrahamCampbell starred nunomaduro / zero - framework GrahamCampbell starred nunomaduro / laravel - zero happyAnger6 created repository happyAnger6 / nodejs_chatroom viosey starred nitely / Spirit lbgws2 starred Germey / TaobaoMM EasyChris starred ageitgey / face_recognition callmewhy starred macmade / GitHubUpdates sindresorhus starred sholladay / squatter SamyPesse starred graphcool / chromeless wbotelhos starred tkadlec / grunt - perfbudget wbotelhos created repository wbotelhos / eggy leohxj starred MacGesture / MacGesture GrahamCampbell starred GrahamCampbell / Analyzer EasyChris starred golang / go mitulgolakiya starred veltman / flubber liaoyuming pushed to student at Germey / SecurityCourse leohxj starred jasonslyvia / a - cartoon - intro - to - redux - cn ruanyf starred ericchiang / pup ruanyf starred bpesquet / thejsway louwailou forked Germey / ScrapyTutorial to louwailou / ScrapyTutorial Lving forked shadowsocksr - backup / shadowsocksr to Lving / shadowsocksr qifuren1985 starred Germey / ADSLProxyPool QWp6t starred laravel / framework Germey [ '1016903103@qq.com' , 'cqc@cuiqingcai.com' ] |
可以發(fā)現(xiàn),我們成功獲取到關(guān)注的人的動(dòng)態(tài)信息和個(gè)人的昵稱及綁定郵箱。模擬登錄成功!
6. 本節(jié)代碼
本節(jié)代碼地址:https://github.com/Python3WebSpider/GithubLogin。
7. 結(jié)語(yǔ)
我們利用 requests 的 Session 實(shí)現(xiàn)了模擬登錄操作,其中最重要的還是分析思路,只要各個(gè)參數(shù)都成功獲取,那么模擬登錄是沒(méi)有問(wèn)題的。
登錄成功,這就相當(dāng)于建立了一個(gè) Session 會(huì)話,Session 對(duì)象維護(hù)著 Cookies 的信息,直接請(qǐng)求就會(huì)得到模擬登錄成功后的頁(yè)面。
以上就是Python3以GitHub為例來(lái)實(shí)現(xiàn)模擬登錄和爬取的實(shí)例講解的詳細(xì)內(nèi)容,更多關(guān)于Python3爬蟲(chóng)以GitHub為例來(lái)實(shí)現(xiàn)模擬登錄和爬取的資料請(qǐng)關(guān)注服務(wù)器之家其它相關(guān)文章!
原文鏈接:https://www.py.cn/spider/example/14477.html