querylist采集微信公眾號文章(爬取大牛用微信公眾號爬取程序的難點(diǎn)及解決辦法)
優(yōu)采云 發(fā)布時(shí)間: 2022-03-11 16:25querylist采集微信公眾號文章(爬取大牛用微信公眾號爬取程序的難點(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ě)得很詳細。
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ----------------------
系統的基本思路是在A(yíng)ndroid模擬器上運行微信,在模擬器上設置代理,通過(guò)代理服務(wù)器截取微信數據,將獲取到的數據發(fā)送給自己的程序進(jìn)行處理。
需要準備的環(huán)境:nodejs、anyproxy代理、安卓模擬器
Nodejs下載地址:我下載的是windows版本的,直接安裝就好了。安裝后直接運行 C:\Program Files\nodejs\npm.cmd 會(huì )自動(dòng)配置環(huán)境。
anyproxy安裝:按照上一步安裝nodejs后,直接在cmd中運行npm install -g anyproxy即可安裝
網(wǎng)上的安卓模擬器就好了,有很多。
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ----------------------------------
首先安裝代理服務(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è)界面,用來(lái)顯示http傳輸的數據。
點(diǎn)擊上方紅框中的菜單,會(huì )出現一個(gè)二維碼。用安卓模擬器掃碼識別。模擬器(手機)會(huì )下載證書(shū)并安裝。
現在準備為模擬器設置代理,代理模式設置為手動(dòng),代理ip為運行anyproxy的機器的ip,端口為8001
準備工作到這里基本完成。在模擬器上打開(kāi)微信,打開(kāi)一個(gè)公眾號的文章,就可以從剛剛打開(kāi)的web界面看到anyproxy抓取的數據:
上圖紅框是微信文章的鏈接,點(diǎn)擊查看具體數據。如果響應正文中沒(méi)有任何內容,則可能是證書(shū)安裝有問(wèn)題。
如果頂部清晰,您可以向下。
這里我們依靠代理服務(wù)來(lái)抓取微信數據,但是我們不能抓取一條數據自己操作微信,所以還是手動(dòng)復制比較好。所以我們需要微信客戶(hù)端自己跳轉到頁(yè)面。這時(shí)可以使用anyproxy攔截微信服務(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),里面的注釋也解釋的很清楚。順著(zhù)邏輯去理解就好,問(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è)面可以向下滾動(dòng)。向下滾動(dòng)會(huì )觸發(fā)js事件發(fā)送請求獲取json數據(下一頁(yè)的內容)。還有公眾號文章的鏈接,以及文章的閱讀和點(diǎn)贊鏈接(返回json數據)。這些環(huán)節的形式是固定的,可以通過(guò)邏輯判斷加以區分。這里有個(gè)問(wèn)題,如果歷史頁(yè)面需要一路爬取怎么辦。我的想法是通過(guò)js模擬鼠標向下滑動(dòng),從而觸發(fā)請求提交下一部分列表的加載?;蛘咧苯邮褂胊nyproxy分析下載請求,直接向微信服務(wù)器發(fā)出這個(gè)請求。但是有一個(gè)問(wèn)題是如何判斷沒(méi)有剩余數據。我正在抓取最新數據。我暫時(shí)沒(méi)有這個(gè)要求,但以后可能需要。如果需要,您可以嘗試一下。