>文章背景: 公司最近在做現在很火的一個短視頻數據分析的項目,其中有一個功能需要快手直播間的數據,比如觀看直播間的人數,用戶彈幕數據,用戶的打賞信息。本來是有專門做python爬蟲的小哥,這個小哥是懵的,前端的事情還得前端來解決,沒辦法事情分配到我這里來了,一步步一分析的過程比較枯燥且乏味,不過別有一番樂趣,本文較長,將全程記錄此次難題的處理。
接到這個需求,我看了看快手直播間的代碼,webpack打包混淆后的js代碼就是一座屎山啊,那特么是給機器看的啊。 一開始我是拒絕的,畢竟壓縮加混淆的3W5千行代碼的文件就有好多個,看一眼就想打人,咋分析。
但是,作為一名孱弱無力的弱小前端,再苦再難也要堅強,畢竟要洽飯的嘛。
分析下此次目的:
1.騙過快手服務器,連接到快手直播間的websocket,讓它乖乖把消息推送到我們自己的服務器
2. 找到快手是采用何種方式對websocket傳輸的blob數據進行編碼與解碼
## 先來看看快手的websocket

可以看到不停的閃爍,服務器再不停地往客戶端推消息
## 首先找到對應需要分享的js文件
既然是分析websocket那我們首先得知道在那座屎山里游泳,打開快手直播間,F12查看源碼,搜索websocket關鍵字

可以看到,有三個文件出現了websocket關鍵字。
1.app.js
2.common.js
3.vendor.js
從我們以往的經驗可以知道 app.js應該是主要的邏輯,vendor.js應該是一些依賴庫的打包,common.js不知道做什么的,但是從命名應該可以猜出是封裝了共用的庫。 然后websocket關鍵字出現最多地方就是common.js,通過本人的對每個文件的分析,果然如此common.js這個32623行混淆過的js就是我們要打的大boss。
## 添加代理 將快手的js代理到本地來調試
這個時候我們打開這個common.js將壓縮后的代碼 展開

因為代碼3W多行代碼,我們發現無法編輯,除了打個斷點 好像什么都不能做,我們此刻要分析就迫切需要編輯調試這個代碼,所以這個時候我們需要用到一個利器charles
> Charles其實是一款代理服務器,通過過將自己設置成系統(電腦或者瀏覽器)的網絡訪問代理服務器,然后截取請求和請求結果達到分析抓包的目的。
具體使用不再累述,檢索下到處都是教程。
安裝好charlses后 ,因為快手直播間采用的https協議,需要安裝下證書,如下圖

點下就完事了,安裝好證書,可以設置下只監聽https的443端口
然后將快手的common.js下載到本地文件夾,在charsles中如下設置


這個時候,我們刷新頁面,即可以在本地就可以隨意用vscode編輯調試線上的快手直播間的js啦。
##猜測關鍵字找到關鍵的函數
這個時候通過一些猜測,比如從websocket關鍵字 一步一步往上推 是的
雖然混淆打包了,但是有很多的很多的關鍵字,需要耐著心去一步一步的看什么 t 函數 a函數 b函數,這期間的過程沒什么可寫的,但是這個過程是極其乏味與痛苦。
通過2天半的艱苦分析,總算將大致的關鍵字邏輯理順了,所有的socket消息發出去通過以下方法

我們將他console出來看看,找到了對應的關鍵字

這里對應說以下,通過之前的分析,我們大概梳理了快手直播間的websocket大致流程:
1.任何連接 任何端都可以連接,但是連接后必須要在50秒內發送第一個包以建立連接,不然服務器會主動斷開
2.每隔20秒發送一次心跳包
我們看到第一個包的數據如下:
```
. payload:
. liveStreamId:"lG02idsTiKU"
. pageId:"RFwi38MUiJQVqiUF\_1567150731045"
3token:"+bNZZ0V7XPjk5Eq7bHNxlGNPJUVkhBVKcmiE4cP+AkAxQaN5Fe17fqap9aCC9VNP97C3VboO2oIjjIgPOuI2qw=="
. type:"CS\_ENTER\_ROOM"
```
其中liveStreamId,pageId可以在頁面seesion中找到,token可以在頁面中找到。
嗯這里看起來好像就做完啦。但是我們拿到的這個數據是在3W5千行代碼中未經編碼前的數據,
快手在websocket中并不會以json的格式傳輸數據,而是采用二進制編碼后數據傳輸。
我們在調試中將其輸出編碼后的

可以看到,被編碼成了arrayBuffer了,我們需要知道她如何編碼的,我們才能自由的將對應的數據編碼發送發哦快手的服務器,且之后收到了數據,也需要將對于的數據,還原成我們能看懂的json數據。
## 解碼與編碼
事情到了這里 又卡住了
通過分析

可以看到 調用了 _.encode _.decode 兩個方法,我們猜測 就是使用_這個對象的方法,但是我們將他輸出來,卻發現如下:


這個時候又是懵的,壓根看不懂,為啥調用下這個方法就將對象編碼成arrayBuffer了啊 再上推也找不,感覺線索斷了(但是如果使用過谷歌protobuf 應該能從y.lookupType這個關鍵字得到啟發瞬間明白使用了什么,但是當時壓根沒用過,所以自然看到這個會很敏感,但當時我沒用過所以沒讓我敏感起來)。
接著繼續往上反推 推到了這個方法,
```
$Writer.create()
```
這個方法我當時不知道什么意思,但是這個函數必然是某個框架的構造create方法,所以我們需要知道 $Writer是什么框架的方法,于是整個百度谷歌了個遍,找到一篇文章
> [Angular2+ 使用 Protocol Buffers 和 websocket]([https://www.jianshu.com/p/cdb12cbde506?utm\_campaign=studygolang.com&utm\_medium=studygolang.com&utm\_source=studygolang.com](https://www.jianshu.com/p/cdb12cbde506?utm_campaign=studygolang.com&utm_medium=studygolang.com&utm_source=studygolang.com))
其中作者在文末,將**Protocol.js 文件源碼:**上傳上了,然后被檢索匹配到了,這個時候豁然開朗,原來就用的這個框架哦。
接著我們找到[protocol.js對應的github地址]([https://github.com/protobufjs/protobuf.js](https://github.com/protobufjs/protobuf.js))
學習一邊昨用這個框架
這個時候我們知道他用了什么框架去編碼這個格式,所以我們在看看對應的代碼即可,然后在起打包的文件中找到 類似于文件的map 的對象,根據這個對象去寫對應的代碼,此處不再累述。
簡單建立鏈接的數據編碼過程如下:

## 最終結果
我們在node中直接起個websocket服務,并對應我們之前折騰了很久的編碼與解碼,直接連接快手服務端,讓它把消息數據乖乖推過來。

解碼后用node寫入在data.json中數據:

完美!
## 總結
限于文字的表現力,與自己的精力時間,不能把每一步都詳細的寫出來,實際做了大概3天,遇到的困難遠比穩重簡單的描述多
這次問題的總結的話就是:
1. 冷靜分析
2. 耐心,耐心
- 前言
- 工作中的一些記錄
- 破解快手直播間的webSocket的連接
- 快手「反」反爬蟲的研究記錄
- HTML AND CSS
- 遇到的一些還行的css筆試題
- css常見面試題
- JavaScript 深度剖析
- ES6到ESNext新特性
- 關于http與緩存
- 關于頁面性能
- 關于瀏覽器的重排(reflow、layout)與重繪
- 手寫函數節流
- 手寫promise
- 手寫函數防抖
- 手寫圖片懶加載
- 手寫jsonp
- 手寫深拷貝
- 手寫new
- 數據結構和算法
- 前言
- 時間復雜度
- 棧
- 隊列
- 集合
- 字典
- 鏈表
- 樹
- 圖
- 堆
- 排序
- 搜索
- Webpack
- Webpack原理與實踐
- Vue
- Vuejs的Virtual Dom的源碼實現
- minVue
- Vuex實現原理
- 一道關于diff算法的面試題
- Vue2源碼筆記:源碼目錄設計
- vue-router源碼分析(v4.x)
- React及周邊
- 深入理解redux(一步步實現一個 redux)
- React常見面試題匯總
- Taro、小程序等
- TypeScript
- CI/CD
- docker踩坑筆記
- jenkins
- 最后