# 引子
最近偶爾在極客學(xué)院看一會(huì)教程視頻,主要是擴(kuò)展視野, 感覺有的視頻教程的質(zhì)量還是不錯(cuò)的,至少能夠把人帶入門。
然而,高質(zhì)量視頻要盈利,學(xué)院針對(duì)*非年度會(huì)員*僅提供第一章節(jié)的試看,就是想誘惑你,注冊(cè),消費(fèi)。
近期學(xué)院有活動(dòng),VIP試用可以通過邀請(qǐng)方式來續(xù)期,會(huì)員A邀請(qǐng)好友B,B通過鏈接注冊(cè)成功后,A和B都同時(shí)會(huì)增加一個(gè)月的會(huì)員。
就是這里,會(huì)員不是關(guān)鍵,關(guān)鍵是有相對(duì)長一點(diǎn)的時(shí)間,可以收集各類教程視頻,是不是可以整一個(gè)這樣的程序:
> 自動(dòng)登陸學(xué)院,爬取分類教程頁面,對(duì)頁面分析出視頻地址,然后分別存儲(chǔ)視頻到本地?
# 初步分析
## 登錄認(rèn)證
學(xué)院的登錄認(rèn)證支持兩種,一種使用通過手機(jī)注冊(cè)驗(yàn)證成為學(xué)院會(huì)員;另一種第三方認(rèn)證(支持QQ,微博等),通過第三方認(rèn)證登錄后,自動(dòng)成為會(huì)員。
在這里,暫時(shí)實(shí)現(xiàn)使用第三方認(rèn)證登錄方式,后面如有需要再考慮使用學(xué)院賬號(hào)登錄。
## 頁面分析
通過F12,看到學(xué)院播放視頻使用了`video-js`控件,如果在支持HTML5的瀏覽器中,在video塊中是可以看到視頻源`source`的地址,這個(gè)后面再細(xì)作分析。
# 詳細(xì)過程
##? 獲得認(rèn)證碼
抓包分析過程,用到了fiddler和瀏覽器的開發(fā)者工具,用于分析使用瀏覽器登錄過程都做了什么操作
模擬網(wǎng)頁請(qǐng)求主要使用`python`,引用庫: requests, base64, hashlib, rsa等
### 從'QQ登錄'開始
點(diǎn)擊‘QQ登錄’按鈕后,抓包分析請(qǐng)求和回應(yīng):

```
<---請(qǐng)求
GET /connect/qq HTTP/1.1\r\n
Host: passport.jikexueyuan.com\r\n
Referer: http://www.jikexueyuan.com/\r\n
--->回應(yīng)
HTTP/1.1 302 Moved Temporarily\r\n
Location: https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101119675&redirect_uri=http://passport.jikexueyuan.com/connect/success?t=qq&state=19325e260ec40f525abcfa2545b0c9a4&scope=get_user_info\r\n
```
這里有一個(gè)HTTP 302跳轉(zhuǎn)至`https://graph.qq.com/oauth2.0/authorize`,用于獲取'Authorization Code'(請(qǐng)參考`http://open.qq.com/`說明)
騰訊的認(rèn)證使用了OAUTH 2.0的server-side模式,獲取認(rèn)證碼的接口定義如下:
>response_type? 必須? 授權(quán)類型,此值固定為“code”。
>client_id? 必須? 申請(qǐng)QQ登錄成功后,分配給應(yīng)用的appid。
>redirect_uri? 必須? 成功授權(quán)后的回調(diào)地址,必須是注冊(cè)appid時(shí)填寫的主域名下的地址,建議設(shè)置為網(wǎng)站首頁或網(wǎng)站的用戶中心。注意需要將url進(jìn)行URLEncode。
>state? 必須? client端的狀態(tài)值。用于第三方應(yīng)用防止CSRF攻擊,成功授權(quán)后回調(diào)時(shí)會(huì)原樣帶回。請(qǐng)務(wù)必嚴(yán)格按照流程檢查用戶與state參數(shù)狀態(tài)的綁定。
fiddler抓日志看的話,可以看到,就是學(xué)院的通行證使用QQ登錄模塊,向騰訊請(qǐng)求認(rèn)證,主要包含cliet_id和state,redirect_uri為本網(wǎng)站。

然后我們接著看,還可以看到,騰訊graph.qq.com/oauth2.0/authorize模塊會(huì)會(huì)引導(dǎo)至此頁面http://openapi.qzone.qq.com:

```
<---
GET /oauth/show?which=ConfirmPage&display=pc&response_type=code&client_id=101119675&redirect_uri=http://passport.jikexueyuan.com/connect/success?t=qq&state=19325e260ec40f525abcfa2545b0c9a4&scope=get_user_info HTTP/1.1\r\n
Host: openapi.qzone.qq.com\r\n
Referer: http://www.jikexueyuan.com/\r\n
--->
HTTP/1.1 200 OK\r\n
```
?? 如果是瀏覽器,會(huì)繼續(xù)請(qǐng)求下載登錄模塊,騰訊這里使用IFrame顯示:


? ```
<---
GET /cgi-bin/xlogin/appid=716027609&style=23&login_text=授權(quán)并登錄&hide_title_bar=1&hide_border=1&target=self&s_url=http://openapi.qzone.qq.com/oauth/login_jump&pt_3rd_aid=101119675&pt_feedback_link=http://support.qq.com/write.shtml?fid=780&SSTAG=www.jikexueyuan.com.appid101119675 HTTP/1.1\r\n
Host: xui.ptlogin2.qq.com\r\n
Referer: http://www.jikexueyuan.com/\r\n
--->
HTTP/1.1 200 OK\r\n
```
??? 這里就出現(xiàn)了登錄按鈕,當(dāng)然也有掃碼登錄,這里我只分析了無驗(yàn)證登錄。我們繼續(xù)分析,輸入QQ賬號(hào)和密碼然后點(diǎn)擊“授權(quán)并登錄”。
??? 瀏覽器會(huì)自動(dòng)登陸,并且導(dǎo)向到學(xué)院主頁,我們看一下fiddler都抓到了什么:
?? 1. 校驗(yàn),返回是否有效登錄,并且返回是否需要驗(yàn)證碼
???2. 登錄,這里就是關(guān)鍵的提交登錄代碼
?? 3. 登錄跳轉(zhuǎn)
?? 4. 上報(bào),一個(gè)是mstats_report,一個(gè)是report_vm
? ?5. 最后是請(qǐng)求授權(quán)碼,如果有返回值,無論成功與否,騰訊鑒權(quán)平臺(tái)根據(jù)redirect_url自動(dòng)跳轉(zhuǎn)
?? 這個(gè)步驟有點(diǎn)多,但是3,4步是否必要需要驗(yàn)證(我是實(shí)現(xiàn)了)。還是繼續(xù)分析HTTP交互過程。
? 1. 請(qǐng)求校驗(yàn),返回是否有效登錄,并且返回是否需要驗(yàn)證碼:
```
<---請(qǐng)求
method: GET
host: check.ptlogin2.qq.com
Param:
GET /check?regmaster=&pt_tea=1&pt_vcode=1&uin=909066038&appid=716027609&js_ver=10138&js_type=1&login_sig=6*d0PfHlaCk9wcqRt1diUu94fNStHN*zaUujdam*-Y9bAegZRbdjYmphbCgVn*B8&u1=http://openapi.qzone.qq.com/oauth/login_jump
--->回應(yīng)
JSON:
ptui_checkVC('0','!OVV','\x00\x00\x00\x00\x36\x2f\x3f\x36','95acfe9e4e59152feb350ef9065c844acb6881fc7c4915fc96ce9bc91a05b75b0e1b66838644b89cfdf95f4e17b1f657fd43b304d390b2b4','0');
```
這個(gè)處理過程請(qǐng)求的參數(shù)中,login_sig是從cookies取得,其他參數(shù)沒有特殊的,返回值第一個(gè)標(biāo)識(shí)是否需要校驗(yàn)碼,'0'標(biāo)識(shí)不需要,第二個(gè)為校驗(yàn)碼,登錄時(shí)需要使用。第三個(gè)為轉(zhuǎn)換后的賬號(hào),第四個(gè)為pt_verifysession_v1可以從cookies中取得,登錄時(shí)使用。
? 2. 登錄,這里就是關(guān)鍵的提交登錄代碼
```
<---請(qǐng)求
GET /login?u=909066038&verifycode=!OVV&pt_vcode_v1=0&pt_verifysession_v1=95acfe9e4e59152feb350ef9065c844acb6881fc7c4915fc96ce9bc91a05b75b0e1b66838644b89cfdf95f4e17b1f657fd43b304d390b2b4&p=YNMEEekeNoSmg9XjMRICahp6OF8iPOYcfytn7Yu
host: ptlogin2.qq.com
--->回應(yīng)
JSON:
ptuiCB('0','0','http://openapi.qzone.qq.com/oauth/login_jump','0','\347\231\273\345\275\225\346\210\220\345\212\237\357\274\201', 'Yo\/jyyo');
```
? 登錄這里有個(gè)參數(shù)需要注意,就是密碼,p為加密后的密碼,騰訊的加密方法可以參考c_login_2.js實(shí)現(xiàn)。
? 3.登錄跳轉(zhuǎn),請(qǐng)求了http://openapi.qzone.qq.com/oauth/login_jump,不用分析
? 4.上報(bào),一個(gè)是mstats_report,一個(gè)是report_vm, 不用分析
? 5. 最后是請(qǐng)求授權(quán)碼,如果有返回值,無論成功與否,騰訊鑒權(quán)平臺(tái)根據(jù)redirect_url自動(dòng)跳轉(zhuǎn)
```
<---請(qǐng)求
Post: 注意是post
host: https://graph.qq.com/oauth2.0/authorize
--->回應(yīng)
??參考下表

```
?? 至此,以我跳躍的思路,描述完從登錄到獲取鑒權(quán)碼的過程,下一篇進(jìn)行編碼。