querylist采集微信公眾號文章(爬取大牛用微信公眾號爬取程序的難點(diǎn)及解決辦法)
優(yōu)采云 發(fā)布時(shí)間: 2022-01-04 06:16querylist采集微信公眾號文章(爬取大牛用微信公眾號爬取程序的難點(diǎn)及解決辦法)
最近需要爬取微信公眾號的文章信息。上網(wǎng)查了一下,發(fā)現微信公眾號的難點(diǎn)是公眾號文章的鏈接在PC端打不開(kāi)。必須使用微信自帶的瀏覽器(獲取微信客戶(hù)端的補充參數,才能在其他平臺打開(kāi)),給爬蟲(chóng)程序帶來(lái)很大的麻煩。后來(lái)在知乎上看到了一個(gè)大牛用php寫(xiě)的微信公眾號爬蟲(chóng)程序,他按照大佬的思路直接做了java。改造過(guò)程中遇到了很多細節問(wèn)題,分享給大家。
附上大牛的鏈接文章:寫(xiě)php或者只需要爬取思路的可以直接看這個(gè)。這些想法寫(xiě)得很詳細。
----------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------------------
系統的基本思想是在安卓模擬器上運行微信。模擬器設置代理,通過(guò)代理服務(wù)器攔截微信數據,并將獲取到的數據發(fā)送給自己的程序進(jìn)行處理。
需要準備的環(huán)境:nodejs、anyproxy代理、Android模擬器
nodejs下載地址:我下載的是windows版本的,直接下載安裝就可以了。安裝完成后直接運行C:\Program Files\nodejs\npm.cmd自動(dòng)配置環(huán)境。
anyproxy安裝:上一步安裝好nodejs后,在cmd中直接運行npm install -g anyproxy就會(huì )安裝
互聯(lián)網(wǎng)上只有一個(gè) Android 模擬器,很多。
----------------------------------------------- -------------------------------------------------- -------------------------------------------------- ---------------------------------------
首先安裝代理服務(wù)器的證書(shū)。 Anyproxy 默認不解析 https 鏈接。安裝證書(shū)后即可解決。在 cmd 中執行 anyproxy --root 將安裝證書(shū)。之后,您必須在模擬器上下載證書(shū)。
然后輸入anyproxy -i命令開(kāi)啟代理服務(wù)。 (記得加參數?。?/p>
記住這個(gè)ip和端口,然后安卓模擬器的代理就會(huì )用到這個(gè)?,F在用瀏覽器打開(kāi)網(wǎng)頁(yè)::8002/ 這是anyproxy的網(wǎng)頁(yè)界面,用于展示http傳輸數據。
點(diǎn)擊上方紅框中的菜單,會(huì )顯示一個(gè)二維碼。使用安卓模擬器掃碼識別。模擬器(手機)會(huì )下載證書(shū)并安裝。
現在我們準備為模擬器設置代理,代理模式設置為手動(dòng),代理ip為運行anyproxy的機器ip,端口為8001
準備工作到此基本完成。在模擬器上打開(kāi)微信,開(kāi)通公眾號文章。您可以從剛打開(kāi)的網(wǎng)頁(yè)界面看到 anyproxy 捕獲的數據:
上面紅框里是微信文章的鏈接,點(diǎn)進(jìn)去查看具體數據。如果響應正文中沒(méi)有任何內容,則可能是證書(shū)安裝有問(wèn)題。
如果一切順利,你就可以下去了。
這里我們依靠代理服務(wù)來(lái)抓取微信數據,但是我們不能抓取一條數據,只能自己操作微信。最好手動(dòng)復制。所以我們需要微信客戶(hù)端自己跳轉到頁(yè)面。這時(shí)候可以使用anyproxy來(lái)攔截微信服務(wù)器返回的數據,將頁(yè)面跳轉代碼注入其中,然后將處理后的數據返回給模擬器,實(shí)現微信客戶(hù)端的自動(dòng)跳轉。
在anyproxy中打開(kāi)一個(gè)名為rule_default.js的js文件,windows下文件為:C:\Users\Administrator\AppData\Roaming\npm\node_modules\anyproxy\lib
文件中有一個(gè)方法叫replaceServerResDataAsync:function(req,res,serverResData,callback)。該方法負責對anyproxy獲得的數據進(jìn)行各種操作。開(kāi)頭應該只有 callback(serverResData) ;該語(yǔ)句的意思是直接將服務(wù)器響應數據返回給客戶(hù)端。直接把這條語(yǔ)句刪掉,換成下面大牛寫(xiě)的代碼。這里的代碼我沒(méi)有做任何改動(dòng),里面的注釋也解釋的很清楚,按照邏輯來(lái)理解就好了,問(wèn)題不大。
1 replaceServerResDataAsync: function(req,res,serverResData,callback){
2 if(/mp\/getmasssendmsg/i.test(req.url)){//當鏈接地址為公眾號歷史消息頁(yè)面時(shí)(第一種頁(yè)面形式)
3 //console.log("開(kāi)始第一種頁(yè)面爬取");
4 if(serverResData.toString() !== ""){
5 6 try {//防止報錯退出程序
7 var reg = /msgList = (.*?);/;//定義歷史消息正則匹配規則
8 var ret = reg.exec(serverResData.toString());//轉換變量為string
9 HttpPost(ret[1],req.url,"/InternetSpider/getData/showBiz");//這個(gè)函數是后文定義的,將匹配到的歷史消息json發(fā)送到自己的服務(wù)器
10 var http = require('http');
11 http.get('http://xxx/getWxHis', function(res) {//這個(gè)地址是自己服務(wù)器上的一個(gè)程序,目的是為了獲取到下一個(gè)鏈接地址,將地址放在一個(gè)js腳本中,將頁(yè)面自動(dòng)跳轉到下一頁(yè)。后文將介紹getWxHis.php的原理。
12 res.on('data', function(chunk){
13 callback(chunk+serverResData);//將返回的代碼插入到歷史消息頁(yè)面中,并返回顯示出來(lái)
14 })
15 });
16 }catch(e){//如果上面的正則沒(méi)有匹配到,那么這個(gè)頁(yè)面內容可能是公眾號歷史消息頁(yè)面向下翻動(dòng)的第二頁(yè),因為歷史消息第一頁(yè)是html格式的,第二頁(yè)就是json格式的。
17 //console.log("開(kāi)始第一種頁(yè)面爬取向下翻形式");
18 try {
19 var json = JSON.parse(serverResData.toString());
20 if (json.general_msg_list != []) {
21 HttpPost(json.general_msg_list,req.url,"/xxx/showBiz");//這個(gè)函數和上面的一樣是后文定義的,將第二頁(yè)歷史消息的json發(fā)送到自己的服務(wù)器
22 }
23 }catch(e){
24 console.log(e);//錯誤捕捉
25 }
26 callback(serverResData);//直接返回第二頁(yè)json內容
27 }
28 }
29 //console.log("開(kāi)始第一種頁(yè)面爬取 結束");
30 }else if(/mp\/profile_ext\?action=home/i.test(req.url)){//當鏈接地址為公眾號歷史消息頁(yè)面時(shí)(第二種頁(yè)面形式)
31 try {
32 var reg = /var msgList = \'(.*?)\';/;//定義歷史消息正則匹配規則(和第一種頁(yè)面形式的正則不同)
33 var ret = reg.exec(serverResData.toString());//轉換變量為string
34 HttpPost(ret[1],req.url,"/xxx/showBiz");//這個(gè)函數是后文定義的,將匹配到的歷史消息json發(fā)送到自己的服務(wù)器
35 var http = require('http');
36 http.get('xxx/getWxHis', function(res) {//這個(gè)地址是自己服務(wù)器上的一個(gè)程序,目的是為了獲取到下一個(gè)鏈接地址,將地址放在一個(gè)js腳本中,將頁(yè)面自動(dòng)跳轉到下一頁(yè)。后文將介紹getWxHis.php的原理。
37 res.on('data', function(chunk){
38 callback(chunk+serverResData);//將返回的代碼插入到歷史消息頁(yè)面中,并返回顯示出來(lái)
39 })
40 });
41 }catch(e){
42 //console.log(e);
43 callback(serverResData);
44 }
45 }else if(/mp\/profile_ext\?action=getmsg/i.test(req.url)){//第二種頁(yè)面表現形式的向下翻頁(yè)后的json
46 try {
47 var json = JSON.parse(serverResData.toString());
48 if (json.general_msg_list != []) {
49 HttpPost(json.general_msg_list,req.url,"/xxx/showBiz");//這個(gè)函數和上面的一樣是后文定義的,將第二頁(yè)歷史消息的json發(fā)送到自己的服務(wù)器
50 }
51 }catch(e){
52 console.log(e);
53 }
54 callback(serverResData);
55 }else if(/mp\/getappmsgext/i.test(req.url)){//當鏈接地址為公眾號文章閱讀量和點(diǎn)贊量時(shí)
56 try {
57 HttpPost(serverResData,req.url,"/xxx/getMsgExt");//函數是后文定義的,功能是將文章閱讀量點(diǎn)贊量的json發(fā)送到服務(wù)器
58 }catch(e){
59
60 }
61 callback(serverResData);
62 }else if(/s\?__biz/i.test(req.url) || /mp\/rumor/i.test(req.url)){//當鏈接地址為公眾號文章時(shí)(rumor這個(gè)地址是公眾號文章被辟謠了)
63 try {
64 var http = require('http');
65 http.get('http://xxx/getWxPost', function(res) {//這個(gè)地址是自己服務(wù)器上的另一個(gè)程序,目的是為了獲取到下一個(gè)鏈接地址,將地址放在一個(gè)js腳本中,將頁(yè)面自動(dòng)跳轉到下一頁(yè)。后文將介紹getWxPost.php的原理。
66 res.on('data', function(chunk){
67 callback(chunk+serverResData);
68 })
69 });
70 }catch(e){
71 callback(serverResData);
72 }
73 }else{
74 callback(serverResData);
75 }
76 //callback(serverResData);
77 },
這里是一個(gè)簡(jiǎn)單的解釋。微信公眾號歷史新聞頁(yè)面的鏈接有兩種形式:一種以/mp/getmasssendmsg開(kāi)頭,另一種以/mp/profile_ext開(kāi)頭。歷史頁(yè)面可以關(guān)閉。如果被拒絕,則會(huì )觸發(fā)一個(gè)js事件,發(fā)送獲取json數據(下一頁(yè)內容)的??請求。還有公眾號文章的鏈接,以及文章的閱讀量和喜歡的鏈接(返回json數據)。這些鏈接的形式是固定的,可以通過(guò)邏輯判斷來(lái)區分。這里的問(wèn)題是,如果所有的歷史頁(yè)面都需要爬取,怎么做。我的想法是模擬鼠標滑過(guò)js觸發(fā)提交加載列表下一部分的請求?;蛘咧苯邮褂胊nyproxy分析滑動(dòng)加載請求,直接將請求發(fā)送到微信服務(wù)器。但是如何判斷沒(méi)有剩余數據一直存在問(wèn)題。我正在抓取最新數據。我暫時(shí)沒(méi)有這個(gè)需求,以后可能需要。有需要的可以試試。