采集方案分析對比
目前主流的抓取公眾號文章及動態(tài)信息不同采集方案對比如下:
由上圖可知:
如果需要長期監(jiān)控公眾號實時的文章眉孩,我推薦使用逆向的方式收叶;
如果要做獲取文章閱讀點贊評論量或搜狗微信轉永久鏈接等接口,推薦使用萬能key的方式菇夸;
至于中間人的方式琼富,技術門檻低,開發(fā)周期短庄新,如果要監(jiān)控的公眾號不多鞠眉,且實效性要求不那么高,我推薦使用這種方式择诈。
下面將詳細介紹基于中間人方式采集的原理
采集方案詳解
基于中間人方式
采集原理
中間人好比中介械蹋,這里指抓包工具,大致的原理圖如下
微信客戶端之所以可以看到文章信息羞芍,是因為請求了微信的服務器哗戈,服務器收到請求后,將對應的文章返給客戶端荷科。這里我們通過抓包工具(中間人)攔截數(shù)據(jù)唯咬,將攔截到的文章數(shù)據(jù)解析入庫,就完成了一次簡單的數(shù)據(jù)抓取畏浆。
那么如何實現(xiàn)多個文章自動抓取胆胰,及列表頁自動翻頁呢】袒瘢總不能人肉去點吧煮剧。那么最先想到的是自動化工具,比如大家都知道的按鍵精靈将鸵。但是這種自動化工具如何與抓包工具交互勉盅,是個問題。我們要保證在數(shù)據(jù)被攔截入庫之后顶掉,再去點擊下一個抓取的目標草娜,又或者當網絡異常時,自動化工具如何檢測出來痒筒,然后重刷當前頁面宰闰,發(fā)起請求。即使可以實現(xiàn)簿透,應該也很麻煩移袍,所以沒采用這種方法。本人也不喜歡自動化工具老充,總感覺它不穩(wěn)定葡盗。。啡浊。
既然微信文章界面是html的觅够,我們可以嵌入js嘛胶背,讓他自動跳轉。那么如何在文章和源代碼里嵌入自己的js呢喘先?這時中間人就派上用場了贫堰,既然他可以攔截數(shù)據(jù)闷串,當然可以修改數(shù)據(jù)戳葵,再返回給客戶端躲株。因此這種方式是可行的。
代碼解析
知道了中間人的原理涤姊,下面說說代碼如何實現(xiàn)直焙。這里所用語言為 python3
,抓包工具為 mitmproxy
. 代理地址倉庫為:https://github.com/striver-ing/wechat-spider
可先下載代碼砂轻,然后對照本文去看代碼
本項目的目錄結構為:
wechat-spider
├── config.py # 讀取配置文件
├── config.yaml # 配置文件
├── core # 代碼的核心
│ ├── capture_packet.py # 抓包代碼(中間人)
│ ├── data_pipeline.py # 數(shù)據(jù)入庫
│ ├── deal_data.py # 數(shù)據(jù)處理
│ └── task_manager.py # 任務調度
├── create_tables.py # 創(chuàng)建表
├── db # 數(shù)據(jù)庫的封裝
│ ├── mysqldb.py # mysql數(shù)據(jù)庫
│ └── redisdb.py # redis數(shù)據(jù)庫
├── run.py # 啟動入口
└── utils # 工具包
├── log.py # 日志
├── selector.py # xpath解析工具
└── tools.py # 一些函數(shù)的封裝
capture_packet.py
本模塊代碼用于攔截微信服務端到客戶端的數(shù)據(jù)奔誓,然后將攔截到的數(shù)據(jù)交給deal_data.py 處理,再注入js返回給微信客戶端搔涝。
紅框框住的為攔截的數(shù)據(jù)包規(guī)則厨喂,比如返回的數(shù)據(jù)包地址中包含 /s?__biz=
,那么該數(shù)據(jù)包的數(shù)據(jù)就會被攔截庄呈。具體每個規(guī)則代表什么數(shù)據(jù)包蜕煌,代碼中有注釋說明,可對應查看
注入js的代碼為
next_page 為所注入的js诬留,值為task_manager.py中返回的斜纪,如下:
核心js為
<script>setTimeout(function(){window.location.href='url';},sleep_time);</script>
即設置了個定時器,在一定的間隔后文兑,跳轉到指定的url盒刚。url 即為我們要抓取的下一個目標,可以為文章地址绿贞,可以為歷史頁面的下一頁地址等因块。
坑
坑1:列表頁第一頁為html,可注入js籍铁,之后再翻頁時數(shù)據(jù)包的格式為json涡上。注入js不生效。因此需要改返回頭才可以
坑2:文章頁面有安全機制拒名,外部注入的js不生效吩愧,也需要改返回的頭。如下:
優(yōu)化
為了使微信客戶端頁面加載更快增显,減少沒必要的網絡請求雁佳。我們可以去掉頁面中的圖片及視頻,代碼如下:
這部分代碼是把返回給微信客戶端數(shù)據(jù)里的img標簽替換為空,那么客戶端就自然不加載圖片了甘穿,不加載視頻的原理一樣腮恩。
<font color='red'>這個模塊的代碼為核心中的核心梢杭,也是中間人全部的代碼温兼,若第一遍沒讀懂,可反復理解幾遍武契,再往下看</font>
deal_data.py
本模塊代碼為數(shù)據(jù)清洗入庫募判,代碼如下:
__parse_account_info:解析公眾號信息
__parse_article_list與deal_article_list:解析文章列表
deal_article:解析文章
deal_article_dynamic_info:解析文章動態(tài)信息,閱讀咒唆、點贊届垫、評論量
deal_comment:解析評論信息
get_task:獲取下一個任務
此處有個細節(jié),處理完數(shù)據(jù)后全释,要返回需要注入的js(即接下來要抓取的頁面)給capture_packet.py装处,以便后續(xù)自動抓取其他文章或歷史列面內容。但閱讀點贊評論量與評論內容這倆接口是在訪問文章地址時間接請求的浸船,因此這倆解析函數(shù)不需要返回注入的js妄迁。
具體的代碼執(zhí)行邏輯如上圖。此處建議自己抓下數(shù)據(jù)包去分析分析李命,再結合代碼登淘,這樣便于理解
task_manager.py
本模塊為任務管理,獲取任務時首先從redis中取封字,若redis中沒有黔州,再從mysql中取,然后添加到redis中
next_page 中 關鍵的跳轉代碼為:
跳轉到下一個url
<script>setTimeout(function(){{window.location.href='{url}';}},{sleep_time_msec});</script>
沒任務時當前頁面在一定時間間隔后刷新
<script>setTimeout(function(){{window.location.reload();}},{sleep_time_msec});</script>
之所以沒任務時要在一定時間間隔后刷新阔籽,是為了觸發(fā)微信客戶端對服務端的請求流妻,然后中間人才能抓到包,之后才能觸發(fā)本模塊的代碼邏輯執(zhí)行笆制,重新獲取任務合冀。
data_pipeline.py
這個模塊沒啥說的,就是數(shù)據(jù)入庫项贺,本處省略
總結
以上為現(xiàn)階段主流的微信公眾號爬蟲技術方案對比分析
及微信公眾號爬蟲
https://github.com/striver-ing/wechat-spider 代碼刨析君躺。建議先抓下微信的數(shù)據(jù)包分析下,搞清楚微信公眾號數(shù)據(jù)整個請求流程开缎,對理解本代碼很有幫助棕叫。目前7.0以上的手機微信貌似抓不到包了,可以抓取pc端的或者mac端的奕删,協(xié)議是一樣的俺泣。
愿本次分享對您有些許幫助,謝謝~
下期分享預告
智聯(lián)-瑞數(shù)反爬破解
了解更多
歡迎加入知識星球 https://t.zsxq.com/eEmAeae
本星球專注于爬蟲技術分享,通過一些案例詳細講解爬蟲中遇到的問題以及解決手段伏钠。涉及的知識包括但不限于 爬蟲框架刨析横漏、js逆向、中間人熟掂、selenium 缎浇、pyppeteer、Android 逆向赴肚!期待您的加入素跺,和我們一起探討爬蟲技術,拓展爬蟲思維誉券!