免費獲?。何⑿殴娞柵颗廊ava版
優(yōu)采云 發(fā)布時(shí)間: 2020-09-06 17:21微信公眾號批量抓取Java版本
最近,我們需要抓取微信公眾號的文章信息。我在互聯(lián)網(wǎng)上搜索后發(fā)現,抓取微信官方賬號的困難在于無(wú)法在PC端打開(kāi)官方賬號文章的鏈接。您需要使用WeChat的瀏覽器(獲取WeChat客戶(hù)端的補充參數才能訪(fǎng)問(wèn)其他平臺上的Open),這會(huì )給爬蟲(chóng)程序帶來(lái)很多麻煩。后來(lái),在知乎上,我看到了由一頭大牛用PHP編寫(xiě)的微信官方帳戶(hù)爬網(wǎng)程序,并且根據大佬的想法將其直接制成Java。在轉換過(guò)程中遇到了很多詳細的問(wèn)題,因此請與大家分享。
系統的基本思想是在A(yíng)ndroid模擬器上運行微信,模擬器設置代理,通過(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,它將被安裝
互聯(lián)網(wǎng)上只有一個(gè)Android模擬器。
首先為代理服務(wù)器安裝證書(shū)。默認情況下,Anyproxy不會(huì )解析https鏈接。安裝證書(shū)后,可以解決它。在cmd中執行anyproxy --root將安裝證書(shū),然后必須在模擬器上下載證書(shū)。
然后輸入anyproxy -i命令打開(kāi)代理服務(wù)。 (請記住要添加參數?。?/p>
記住該IP和端口,然后Android*敏*感*詞*的代理將使用此IP和端口?,F在,使用瀏覽器打開(kāi)網(wǎng)頁(yè):: 8002 /這是anyproxy的網(wǎng)絡(luò )界面,用于顯示http傳輸數據。
單擊上方紅色框中的菜單,將顯示QR碼。使用Android模擬器掃描代碼以進(jìn)行識別。*敏*感*詞*(手機)將下載證書(shū)并安裝。
現在我們準備為模擬器設置代理,代理模式設置為手動(dòng),代理ip是運行anyproxy的計算機的ip,端口為8001
準備工作到此基本完成。在模擬器上打開(kāi)微信并開(kāi)設一個(gè)官方帳戶(hù)文章。您可以從剛打開(kāi)的Web界面中查看anyproxy捕獲的數據:
在上方的紅色框中是微信文章的鏈接,單擊進(jìn)入以查看特定數據。如果響應正文中沒(méi)有任何內容,則證書(shū)安裝可能存在問(wèn)題。
如果一切都通過(guò)以上,則可以下去。
在這里,我們依靠代理服務(wù)來(lái)捕獲微信數據,但是我們無(wú)法捕獲數據,而只能自己操作微信。最好手動(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
文件中有一種稱(chēng)為replaceServerResDataAsync的方法:function(req,res,serverResData,callback)。此方法負責對anyproxy獲得的數據進(jìn)行各種操作。開(kāi)頭應該只有callback(serverResData);此語(yǔ)句意味著(zhù)直接將服務(wù)器響應數據返回給客戶(hù)端。直接刪除此語(yǔ)句,并將其替換為Daniel編寫(xiě)的以下代碼。我在這里沒(méi)有對代碼做任何更改,并且內部的注釋也很清楚地解釋了,只需按照邏輯來(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() !== ""){
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)短的解釋。鏈接到微信官方帳戶(hù)歷史新聞頁(yè)面的鏈接有兩種形式:一種以/ mp / getmasssendmsg開(kāi)頭,另一種以/ mp / profile_ext開(kāi)頭。歷史記錄頁(yè)面可以關(guān)閉。如果將其關(guān)閉,則會(huì )觸發(fā)js事件,以發(fā)送請求以獲取json數據(下一頁(yè)內容)。也有指向官方帳戶(hù)文章的鏈接,也有指向文章的閱讀次數和喜歡次數的鏈接(返回json數據)。這些鏈接的形式是固定的,可以通過(guò)邏輯判斷加以區分。這里的問(wèn)題是,如果需要對所有歷史頁(yè)面進(jìn)行爬網(wǎng),該怎么做。我的想法是模擬鼠標在js中向下滑動(dòng),以觸發(fā)提交請求以加載列表的下一部分?;蛘咧苯邮褂胊nyproxy分析滑動(dòng)加載請求,并將請求直接發(fā)送至微信服務(wù)器。但是,如何判斷沒(méi)有剩余數據始終存在問(wèn)題。我正在搜尋最新數據。我暫時(shí)沒(méi)有這個(gè)要求。以后可能需要。如果需要,可以嘗試一下。