激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳細Java批量獲取微信公眾號方法

詳細Java批量獲取微信公眾號方法

2021-02-27 11:11luojiangwen Java教程

本篇文章給大家講解了用JAVA如何實現向爬蟲一樣獲取微信公眾號和其基本信息等,需要你正巧需要,那跟著學習參考下吧。

最近需要爬取微信公眾號的文章信息。在網上找了找發現微信公眾號爬取的難點在于公眾號文章鏈接在pc端是打不開的,要用微信的自帶瀏覽器(拿到微信客戶端補充的參數,才可以在其它平臺打開),這就給爬蟲程序造成很大困擾。后來在知乎上看到了一位大牛用php寫的微信公眾號爬取程序,就直接按大佬的思路整了整搞成java的了。改造途中遇到蠻多細節問題,拿出來分享一下。

系統的基本思路是在安卓模擬器上運行微信,模擬器設置代理,通過代理服務器攔截微信數據,將得到的數據發送給自己的程序進行處理。

需要準備的環境:nodejs,anyproxy代理,安卓模擬器

nodejs下載地址:http://nodejs.cn/download/,我下載的是windows版的,下好直接安裝就行。安裝好后,直接運行c:program files odejs pm.cmd 會自動配置好環境。

anyproxy安裝:按上一步安裝好nodejs之后,直接在cmd運行 npm install -g anyproxy 就會安裝了

安卓模擬器隨便在網上下一個就好了,一大堆。

首先為代理服務器安裝證書,anyproxy默認不解析https鏈接,安裝證書后就可以解析了,在cmd執行anyproxy --root 就會安裝證書,之后還得在模擬器也下載這個證書。

然后輸入anyproxy -i 命令 打開代理服務。(記得加上參數!)

 詳細Java批量獲取微信公眾號方法

記住這個ip和端口,之后安卓模擬器的代理就用這個?,F在用瀏覽器打開網頁:http://localhost:8002/  這是anyproxy的網頁界面,用于顯示http傳輸數據。

詳細Java批量獲取微信公眾號方法

點擊上面紅框框里面的菜單,會出一個二維碼,用安卓模擬器掃碼識別,模擬器(手機)就會下載證書了,安裝上就好了。

現在準備為模擬器設置代理,代理方式設置為手動,代理ip為運行anyproxy機器的ip,端口是8001

詳細Java批量獲取微信公眾號方法

 

到這里準備工作基本完成,在模擬器上打開微信隨便打開一個公眾號的文章,就能從你剛打開的web界面中看到anyproxy抓取到的數據:

詳細Java批量獲取微信公眾號方法

上面紅框內就是微信文章的鏈接,點擊進去可以看到具體的數據。如果response body里面什么都沒有可能證書安裝有問題。

如果上面都走通了,就可以接著往下走了。

這里我們靠代理服務抓微信數據,但總不能抓取一條數據就自己操作一下微信,那樣還不如直接人工復制。所以我們需要微信客戶端自己跳轉頁面。這時就可以使用anyproxy攔截微信服務器返回的數據,往里面注入頁面跳轉代碼,再把加工的數據返回給模擬器實現微信客戶端自動跳轉。

打開anyproxy中的一個叫rule_default.js的js文件,windows下該文件在:c:usersdministratorppdata oaming pm ode_modulesnyproxylib

在文件里面有個叫replaceserverresdataasync: function(req,res,serverresdata,callback)的方法,這個方法就是負責對anyproxy拿到的數據進行各種操作。一開始應該只有callback(serverresdata);這條語句的意思是直接返回服務器響應數據給客戶端。直接刪掉這條語句,替換成大牛寫的如下代碼。這里的代碼我并沒有做什么改動,里面的注釋也解釋的給非常清楚,直接按邏輯看懂就行,問題不大。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
replaceserverresdataasync: function(req,res,serverresdata,callback){
    if(/mp/getmasssendmsg/i.test(req.url)){//當鏈接地址為公眾號歷史消息頁面時(第一種頁面形式)
      //console.log("開始第一種頁面爬取");
      if(serverresdata.tostring() !== ""){
        6         try {//防止報錯退出程序
         var reg = /msglist = (.*?);/;//定義歷史消息正則匹配規則
         var ret = reg.exec(serverresdata.tostring());//轉換變量為string
         httppost(ret[1],req.url,"/internetspider/getdata/showbiz");//這個函數是后文定義的,將匹配到的歷史消息json發送到自己的服務器
         var http = require('http');
          http.get('http://xxx/getwxhis', function(res) {//這個地址是自己服務器上的一個程序,目的是為了獲取到下一個鏈接地址,將地址放在一個js腳本中,將頁面自動跳轉到下一頁。后文將介紹getwxhis.php的原理。
            res.on('data', function(chunk){
            callback(chunk+serverresdata);//將返回的代碼插入到歷史消息頁面中,并返回顯示出來
            })
          });
        }catch(e){//如果上面的正則沒有匹配到,那么這個頁面內容可能是公眾號歷史消息頁面向下翻動的第二頁,因為歷史消息第一頁是html格式的,第二頁就是json格式的。
        //console.log("開始第一種頁面爬取向下翻形式");
          try {
            var json = json.parse(serverresdata.tostring());
            if (json.general_msg_list != []) {
            httppost(json.general_msg_list,req.url,"/xxx/showbiz");//這個函數和上面的一樣是后文定義的,將第二頁歷史消息的json發送到自己的服務器
            }
          }catch(e){
           console.log(e);//錯誤捕捉
          }
          callback(serverresdata);//直接返回第二頁json內容
        }
      }
      //console.log("開始第一種頁面爬取 結束");
    }else if(/mp/profile_ext?action=home/i.test(req.url)){//當鏈接地址為公眾號歷史消息頁面時(第二種頁面形式)
      try {
        var reg = /var msglist = '(.*?)';/;//定義歷史消息正則匹配規則(和第一種頁面形式的正則不同)
        var ret = reg.exec(serverresdata.tostring());//轉換變量為string
        httppost(ret[1],req.url,"/xxx/showbiz");//這個函數是后文定義的,將匹配到的歷史消息json發送到自己的服務器
        var http = require('http');
        http.get('xxx/getwxhis', function(res) {//這個地址是自己服務器上的一個程序,目的是為了獲取到下一個鏈接地址,將地址放在一個js腳本中,將頁面自動跳轉到下一頁。后文將介紹getwxhis.php的原理。
            res.on('data', function(chunk){
            callback(chunk+serverresdata);//將返回的代碼插入到歷史消息頁面中,并返回顯示出來
            })
          });
      }catch(e){
        //console.log(e);
        callback(serverresdata);
      }
    }else if(/mp/profile_ext?action=getmsg/i.test(req.url)){//第二種頁面表現形式的向下翻頁后的json
      try {
        var json = json.parse(serverresdata.tostring());
        if (json.general_msg_list != []) {
          httppost(json.general_msg_list,req.url,"/xxx/showbiz");//這個函數和上面的一樣是后文定義的,將第二頁歷史消息的json發送到自己的服務器
        }
      }catch(e){
        console.log(e);
      }
      callback(serverresdata);
    }else if(/mp/getappmsgext/i.test(req.url)){//當鏈接地址為公眾號文章閱讀量和點贊量時
      try {
        httppost(serverresdata,req.url,"/xxx/getmsgext");//函數是后文定義的,功能是將文章閱讀量點贊量的json發送到服務器
      }catch(e){
 
      }
      callback(serverresdata);
    }else if(/s?__biz/i.test(req.url) || /mp/rumor/i.test(req.url)){//當鏈接地址為公眾號文章時(rumor這個地址是公眾號文章被辟謠了)
      try {
        var http = require('http');
        http.get('http://xxx/getwxpost', function(res) {//這個地址是自己服務器上的另一個程序,目的是為了獲取到下一個鏈接地址,將地址放在一個js腳本中,將頁面自動跳轉到下一頁。后文將介紹getwxpost.php的原理。
          res.on('data', function(chunk){
            callback(chunk+serverresdata);
          })
        });
      }catch(e){
        callback(serverresdata);
      }
    }else{
      callback(serverresdata);
    }
    //callback(serverresdata);
  },
 

這里簡單解釋一下,微信公眾號的歷史消息頁鏈接有兩種形式:一種以 mp.weixin.qq.com/mp/getmasssendmsg 開頭,另一種是 mp.weixin.qq.com/mp/profile_ext 開頭。歷史頁是可以向下翻的,如果向下翻將觸發js事件發送請求得到json數據(下一頁內容)。還有公眾號文章鏈接,以及文章的閱讀量和點贊量的鏈接(返回的是json數據),這幾種鏈接的形式是固定的可以通過邏輯判斷來區分。這里有個問題就是歷史頁如果需要全部爬取到該怎么做到。我的思路是通過js去模擬鼠標向下滑動,從而觸發提交加載下一部分列表的請求。或者直接利用anyproxy分析下滑加載的請求,直接向微信服務器發生這個請求。但都有一個問題就是如何判斷已經沒有余下數據了。我是爬取最新數據,暫時沒這個需求,可能以后要。如果有需求的可以嘗試一下。

下圖是上文中的httppost方法內容。

?
1
function httppost(str,url,path) {//將json發送到服務器,str為json內容,url為歷史消息頁面地址,path是接收程序的路徑和文件名<br>     console.log("開始執行轉發操作");<br>     try{<br>     var http = require('http');<br>     var data = {<br>         str: encodeuricomponent(str),<br>         url: encodeuricomponent(url)<br>     };<br>     data = require('querystring').stringify(data);<br>     var options = {<br>         method: "post",<br>         host: "xxx",//注意沒有http://,這是服務器的域名。<br>         port: xxx,<br>         path: path,//接收程序的路徑和文件名<br>         headers: {<br>             'content-type': 'application/x-www-form-urlencoded; charset=utf-8',<br>             "content-length": data.length<br>         }<br>     };<br>     var req = http.request(options, function (res) {<br>         res.setencoding('utf8');<br>         res.on('data', function (chunk) {<br>             console.log('body: ' + chunk);<br>         });<br>     });<br>     req.on('error', function (e) {<br>         console.log('problem with request: ' + e.message);<br>     });<br>     <br>     req.write(data);<br>     req.end();<br>     }catch(e){<br>         console.log("錯誤信息:"+e);<br>     }<br>     console.log("轉發操作結束");<br> }

做完以上工作,接下來就是按自己業務來完成服務端代碼了,我們的服務用于接收代理服務器發過來的數據進行處理,進行持久化操作,同時向代理服務器發送需要注入到微信的js代碼。針對代理服務器攔截到的幾種不同鏈接發來的數據,我們就需要設計相應的方法來處理這些數據。從anyproxy處理微信數據的js方法replaceserverresdataasync: function(req,res,serverresdata,callback)中,我們可以知道至少需要對公眾號歷史頁數據、公眾號文章頁數據、公眾號文章點贊量和閱讀量數據設計三種方法來處理。同時我們還需要設計一個方法來生成爬取任務,完成公眾號的輪尋爬取。如果需要爬取更多數據,可以從anyproxy抓取到的鏈接中分析出更多需要的數據,然后往replaceserverresdataasync: function(req,res,serverresdata,callback)中添加判定,攔截到需要的數據發送到自己的服務器,相應的在服務端添加方法處理該類數據就行了。

我是用java寫的服務端代碼。

處理公眾號歷史頁數據方法:

  1. public void getmsgjson(string str ,string url) throws unsupportedencodingexception { 
  2.     // todo auto-generated method stub 
  3.     string biz = ""
  4.     map<string,string> querystrs = httpurlparser.parseurl(url); 
  5.     if(querystrs != null){ 
  6.       biz = querystrs.get("__biz"); 
  7.       biz = biz + "=="
  8.     } 
  9.     /** 
  10.      * 從數據庫中查詢biz是否已經存在,如果不存在則插入, 
  11.      * 這代表著我們新添加了一個采集目標公眾號。 
  12.      */ 
  13.     list<weixin> results = weixinmapper.selectbybiz(biz); 
  14.     if(results == null || results.size() == 0){ 
  15.       weixin weixin = new weixin(); 
  16.       weixin.setbiz(biz); 
  17.       weixin.setcollect(system.currenttimemillis()); 
  18.       weixinmapper.insert(weixin); 
  19.     } 
  20.     //system.out.println(str); 
  21.     //解析str變量 
  22.     list<object> lists = jsonpath.read(str, "['list']"); 
  23.     for(object list : lists){ 
  24.       object json = list; 
  25.       int type = jsonpath.read(json, "['comm_msg_info']['type']"); 
  26.       if(type == 49){//type=49表示是圖文消息 
  27.         string content_url = jsonpath.read(json, "$.app_msg_ext_info.content_url"); 
  28.         content_url = content_url.replace("", "").replaceall("amp;", "");//獲得圖文消息的鏈接地址 
  29.         int is_multi = jsonpath.read(json, "$.app_msg_ext_info.is_multi");//是否是多圖文消息 
  30.         integer datetime = jsonpath.read(json, "$.comm_msg_info.datetime");//圖文消息發送時間 
  31.         /** 
  32.          * 在這里將圖文消息鏈接地址插入到采集隊列庫tmplist中 
  33.          * (隊列庫將在后文介紹,主要目的是建立一個批量采集隊列, 
  34.          * 另一個程序將根據隊列安排下一個采集的公眾號或者文章內容) 
  35.          */ 
  36.         try
  37.           if(content_url != null && !"".equals(content_url)){ 
  38.             tmplist tmplist = new tmplist(); 
  39.             tmplist.setcontenturl(content_url); 
  40.             tmplistmapper.insertselective(tmplist); 
  41.           } 
  42.         }catch(exception e){ 
  43.           system.out.println("隊列已存在,不插入!"); 
  44.         } 
  45.          
  46.         /** 
  47.          * 在這里根據$content_url從數據庫post中判斷一下是否重復 
  48.          */ 
  49.         list<post> postlist = postmapper.selectbycontenturl(content_url); 
  50.         boolean contenturlexist = false
  51.         if(postlist != null && postlist.size() != 0){ 
  52.           contenturlexist = true
  53.         } 
  54.        
  55.          
  56.         if(!contenturlexist){//'數據庫post中不存在相同的$content_url' 
  57.           integer fileid = jsonpath.read(json, "$.app_msg_ext_info.fileid");//一個微信給的id 
  58.           string title = jsonpath.read(json, "$.app_msg_ext_info.title");//文章標題 
  59.           string title_encode = urlencoder.encode(title, "utf-8"); 
  60.           string digest = jsonpath.read(json, "$.app_msg_ext_info.digest");//文章摘要 
  61.           string source_url = jsonpath.read(json, "$.app_msg_ext_info.source_url");//閱讀原文的鏈接 
  62.           source_url = source_url.replace("", ""); 
  63.           string cover = jsonpath.read(json, "$.app_msg_ext_info.cover");//封面圖片 
  64.           cover = cover.replace("", ""); 
  65.           /** 
  66.            * 存入數據庫 
  67.            */ 
  68. //          system.out.println("頭條標題:"+title); 
  69. //          system.out.println("微信id:"+fileid); 
  70. //          system.out.println("文章摘要:"+digest); 
  71. //          system.out.println("閱讀原文鏈接:"+source_url); 
  72. //          system.out.println("封面圖片地址:"+cover);          
  73.            
  74.           post post = new post(); 
  75.           post.setbiz(biz); 
  76.           post.settitle(title); 
  77.           post.settitleencode(title_encode); 
  78.           post.setfieldid(fileid); 
  79.           post.setdigest(digest); 
  80.           post.setsourceurl(source_url); 
  81.           post.setcover(cover); 
  82.           post.setistop(1);//標記一下是頭條內容 
  83.           post.setismulti(is_multi); 
  84.           post.setdatetime(datetime); 
  85.           post.setcontenturl(content_url); 
  86.            
  87.           postmapper.insert(post); 
  88.         } 
  89.        
  90.         if(is_multi == 1){//如果是多圖文消息 
  91.           list<object> multilists = jsonpath.read(json, "['app_msg_ext_info']['multi_app_msg_item_list']"); 
  92.           for(object multilist : multilists){ 
  93.             object multijson = multilist;          
  94.             content_url = jsonpath.read(multijson, "['content_url']").tostring().replace("", "").replaceall("amp;", "");//圖文消息鏈接地址 
  95.             /** 
  96.              * 這里再次根據$content_url判斷一下數據庫中是否重復以免出錯 
  97.              */ 
  98.             contenturlexist = false
  99.             list<post> posts = postmapper.selectbycontenturl(content_url); 
  100.             if(posts != null && posts.size() != 0){ 
  101.               contenturlexist = true
  102.             } 
  103.             if(!contenturlexist){//'數據庫中不存在相同的$content_url' 
  104.               /** 
  105.                * 在這里將圖文消息鏈接地址插入到采集隊列庫中 
  106.                * (隊列庫將在后文介紹,主要目的是建立一個批量采集隊列, 
  107.                * 另一個程序將根據隊列安排下一個采集的公眾號或者文章內容) 
  108.                */ 
  109.               if(content_url != null && !"".equals(content_url)){ 
  110.                 tmplist tmplistt = new tmplist(); 
  111.                 tmplistt.setcontenturl(content_url); 
  112.                 tmplistmapper.insertselective(tmplistt); 
  113.               } 
  114.                
  115.               string title = jsonpath.read(multijson, "$.title"); 
  116.               string title_encode = urlencoder.encode(title, "utf-8"); 
  117.               integer fileid = jsonpath.read(multijson, "$.fileid"); 
  118.               string digest = jsonpath.read(multijson, "$.digest"); 
  119.               string source_url = jsonpath.read(multijson, "$.source_url"); 
  120.               source_url = source_url.replace("", ""); 
  121.               string cover = jsonpath.read(multijson, "$.cover"); 
  122.               cover = cover.replace("", "");            
  123. //              system.out.println("標題:"+title); 
  124. //              system.out.println("微信id:"+fileid); 
  125. //              system.out.println("文章摘要:"+digest); 
  126. //              system.out.println("閱讀原文鏈接:"+source_url); 
  127. //              system.out.println("封面圖片地址:"+cover);              
  128.               post post = new post(); 
  129.               post.setbiz(biz); 
  130.               post.settitle(title); 
  131.               post.settitleencode(title_encode); 
  132.               post.setfieldid(fileid); 
  133.               post.setdigest(digest); 
  134.               post.setsourceurl(source_url); 
  135.               post.setcover(cover); 
  136.               post.setistop(0);//標記一下不是頭條內容 
  137.               post.setismulti(is_multi); 
  138.               post.setdatetime(datetime); 
  139.               post.setcontenturl(content_url); 
  140.                
  141.               postmapper.insert(post); 
  142.                
  143.             } 
  144.           } 
  145.         }      
  146.       }    
  147.     } 
  148.   } 
處理公眾號文章頁的方法:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public string getwxpost() {
    // todo auto-generated method stub
    /**
     * 當前頁面為公眾號文章頁面時,讀取這個程序
     * 首先刪除采集隊列表中load=1的行
     * 然后從隊列表中按照“order by id asc”選擇多行(注意這一行和上面的程序不一樣)
     */
    tmplistmapper.deletebyload(1);
    list<tmplist> queues = tmplistmapper.selectmany(5);
    string url = "";
    if(queues != null && queues.size() != 0 && queues.size() > 1){
      tmplist queue = queues.get(0);
      url = queue.getcontenturl();
      queue.setisload(1);
      int result = tmplistmapper.updatebyprimarykey(queue);
      system.out.println("update result:"+result);
    }else{
      system.out.println("getpost queues is null?"+queues==null?null:queues.size());
      weixin weixin = weixinmapper.selectone();
      string biz = weixin.getbiz();
      if((math.random()>0.5?1:0) == 1){
        url = "http://mp.weixin.qq.com/mp/getmasssendmsg?__biz=" + biz +
            "#wechat_webview_type=1&wechat_redirect";//拼接公眾號歷史消息url地址(第一種頁面形式)
      }else{
        url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=" + biz +
            "#wechat_redirect";//拼接公眾號歷史消息url地址(第二種頁面形式)
      }
      url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=" + biz +
          "#wechat_redirect";//拼接公眾號歷史消息url地址(第二種頁面形式)
      //更新剛才提到的公眾號表中的采集時間time字段為當前時間戳。
      weixin.setcollect(system.currenttimemillis());
      int result = weixinmapper.updatebyprimarykey(weixin);
      system.out.println("getpost weixin updateresult:"+result);
    }
    int randomtime = new random().nextint(3) + 3;
    string jscode = "<script>settimeout(function(){window.location.href='"+url+"';},"+randomtime*1000+");</script>";
    return jscode;
    
  }

 

處理公眾號點贊量和閱讀量的方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public void getmsgext(string str,string url) {
    // todo auto-generated method stub
    string biz = "";
    string sn = "";
    map<string,string> querystrs = httpurlparser.parseurl(url);
    if(querystrs != null){
      biz = querystrs.get("__biz");
      biz = biz + "==";
      sn = querystrs.get("sn");
      sn = "%" + sn + "%";
    }
    /**
     * $sql = "select * from `文章表` where `biz`='".$biz."'
     * and `content_url` like '%".$sn."%'" limit 0,1;
     * 根據biz和sn找到對應的文章
     */
    post post = postmapper.selectbybizandsn(biz, sn);
    
    if(post == null){
      system.out.println("biz:"+biz);
      system.out.println("sn:"+sn);
      tmplistmapper.deletebyload(1);
      return;
    }
    
//    system.out.println("json數據:"+str);
    integer read_num;
    integer like_num;
    try{
      read_num = jsonpath.read(str, "['appmsgstat']['read_num']");//閱讀量
      like_num = jsonpath.read(str, "['appmsgstat']['like_num']");//點贊量
    }catch(exception e){
      read_num = 123;//閱讀量
      like_num = 321;//點贊量
      system.out.println("read_num:"+read_num);
      system.out.println("like_num:"+like_num);
      system.out.println(e.getmessage());
    }   
    
    /**
     * 在這里同樣根據sn在采集隊列表中刪除對應的文章,代表這篇文章可以移出采集隊列了
     * $sql = "delete from `隊列表` where `content_url` like '%".$sn."%'"
     */
    tmplistmapper.deletebysn(sn);
    
    //然后將閱讀量和點贊量更新到文章表中。
    post.setreadnum(read_num);
    post.setlikenum(like_num);
    postmapper.updatebyprimarykey(post);
    
  }

 

處理跳轉向微信注入js的方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public string getwxhis() {
    string url = "";
    // todo auto-generated method stub
    /**
     * 當前頁面為公眾號歷史消息時,讀取這個程序
     * 在采集隊列表中有一個load字段,當值等于1時代表正在被讀取
     * 首先刪除采集隊列表中load=1的行
     * 然后從隊列表中任意select一行
     */
    tmplistmapper.deletebyload(1);
    tmplist queue = tmplistmapper.selectrandomone();
    system.out.println("queue is null?"+queue);
    if(queue == null){//隊列表為空
      /**
       * 隊列表如果空了,就從存儲公眾號biz的表中取得一個biz,
       * 這里我在公眾號表中設置了一個采集時間的time字段,按照正序排列之后,
       * 就得到時間戳最小的一個公眾號記錄,并取得它的biz
       */
      weixin weixin = weixinmapper.selectone();
      
      string biz = weixin.getbiz();
      url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=" + biz +
          "#wechat_redirect";//拼接公眾號歷史消息url地址(第二種頁面形式)
      //更新剛才提到的公眾號表中的采集時間time字段為當前時間戳。
      weixin.setcollect(system.currenttimemillis());
      int result = weixinmapper.updatebyprimarykey(weixin);
      system.out.println("gethis weixin updateresult:"+result);
    }else{
      //取得當前這一行的content_url字段
      url = queue.getcontenturl();
      //將load字段update為1
      tmplistmapper.updatebycontenturl(url);
    }
    //將下一個將要跳轉的$url變成js腳本,由anyproxy注入到微信頁面中。
    //echo "<script>settimeout(function(){window.location.href='".$url."';},2000);</script>";
    int randomtime = new random().nextint(3) + 3;
    string jscode = "<script>settimeout(function(){window.location.href='"+url+"';},"+randomtime*1000+");</script>";
    return jscode;
  }

以上就是對處理代理服務器攔截到的數據進行處理的程序。這里有一個需要注意的問題,程序會對數據庫中的每個收錄的公眾號進行輪循訪問,甚至是已經存儲的文章也會再次訪問,目的是為了一直更新文章的閱讀數和點贊數。如果需要抓取大量的公眾號建議對添加任務隊列的代碼進行修改,添加條件限制,否則公眾號一多 輪循抓取重復數據將十分影響效率。

至此就將微信公眾號的文章鏈接全部爬取到,而且這個鏈接是永久有效而且可以在瀏覽器打開的鏈接,接下來就是寫爬蟲程序從數據庫中拿鏈接爬取文章內容等信息了。

我是用webmagic寫的爬蟲,輕量好用。

  1. public class spidermodel implements pageprocessor{ 
  2.    
  3.   private static postmapper postmapper; 
  4.    
  5.   private static list<post> posts; 
  6.    
  7.   // 抓取網站的相關配置,包括編碼、抓取間隔、重試次數等 
  8.   private site site = site.me().setretrytimes(3).setsleeptime(100); 
  9.    
  10.   public site getsite() { 
  11.     // todo auto-generated method stub 
  12.     return this.site; 
  13.   } 
  14.    
  15.   public void process(page page) { 
  16.     // todo auto-generated method stub 
  17.     post post = posts.remove(0); 
  18.     string content = page.gethtml().xpath("//div[@id='js_content']").get(); 
  19.     //存在和諧文章 此處做判定如果有直接刪除記錄或設置表示位表示文章被和諧 
  20.     if(content == null){ 
  21.       system.out.println("文章已和諧!"); 
  22.       //postmapper.deletebyprimarykey(post.getid()); 
  23.       return
  24.     } 
  25.     string contentsnap = content.replaceall("data-src""src").replaceall("preview.html""player.html");//快照 
  26.     string contenttxt = htmltoword.striphtml(content);//純文本內容 
  27.      
  28.     selectable metacontent = page.gethtml().xpath("//div[@id='meta_content']"); 
  29.     string pubtime = null
  30.     string wxname = null
  31.     string author = null
  32.     if(metacontent != null){ 
  33.       pubtime = metacontent.xpath("//em[@id='post-date']").get(); 
  34.       if(pubtime != null){ 
  35.         pubtime = htmltoword.striphtml(pubtime);//文章發布時間 
  36.       } 
  37.       wxname = metacontent.xpath("//a[@id='post-user']").get(); 
  38.       if(wxname != null){ 
  39.         wxname = htmltoword.striphtml(wxname);//公眾號名稱 
  40.       } 
  41.       author = metacontent.xpath("//em[@class='rich_media_meta rich_media_meta_text' and @id!='post-date']").get(); 
  42.       if(author != null){ 
  43.         author = htmltoword.striphtml(author);//文章作者 
  44.       } 
  45.     } 
  46.      
  47. //    system.out.println("發布時間:"+pubtime); 
  48. //    system.out.println("公眾號名稱:"+wxname); 
  49. //    system.out.println("文章作者:"+author); 
  50.      
  51.     string title = post.gettitle().replaceall(" """);//文章標題 
  52.     string digest = post.getdigest();//文章摘要 
  53.     int likenum = post.getlikenum();//文章點贊數 
  54.     int readnum = post.getreadnum();//文章閱讀數 
  55.     string contenturl = post.getcontenturl();//文章鏈接 
  56.      
  57.     wechatinfobean wechatbean = new wechatinfobean(); 
  58.     wechatbean.settitle(title); 
  59.     wechatbean.setcontent(contenttxt);//純文本內容 
  60.     wechatbean.setsourcecode(contentsnap);//快照 
  61.     wechatbean.setlikecount(likenum); 
  62.     wechatbean.setviewcount(readnum); 
  63.     wechatbean.setabstracttext(digest);//摘要 
  64.     wechatbean.seturl(contenturl); 
  65.     wechatbean.setpublishtime(pubtime); 
  66.     wechatbean.setsitename(wxname);//站點名稱 公眾號名稱 
  67.     wechatbean.setauthor(author); 
  68.     wechatbean.setmediatype("微信公眾號");//來源媒體類型 
  69.      
  70.     wechatstorage.savewechatinfo(wechatbean); 
  71.      
  72.     //標示文章已經被爬取 
  73.     post.setisspider(1); 
  74.     postmapper.updatebyprimarykey(post); 
  75.      
  76.   }  
  77.    
  78.   public static void startspider(list<post> inposts,postmapper mypostmapper,string... urls){ 
  79.      
  80.     long starttime, endtime; 
  81.     starttime = system.currenttimemillis(); 
  82.     postmapper = mypostmapper; 
  83.     posts = inposts; 
  84.      
  85.     httpclientdownloader httpclientdownloader = new httpclientdownloader();    
  86.     spidermodel spidermodel = new spidermodel(); 
  87.     spider myspider = spider.create(spidermodel).addurl(urls); 
  88.     myspider.setdownloader(httpclientdownloader); 
  89.     try { 
  90.       spidermonitor.instance().register(myspider); 
  91.       myspider.thread(1).run(); 
  92.     } catch (jmexception e) { 
  93.       e.printstacktrace(); 
  94.     } 
  95.      
  96.     endtime = system.currenttimemillis(); 
  97.     system.out.println("爬取時間" + ((endtime - starttime) / 1000) + "秒--"); 
  98.      
  99.   } 
  100.    

其它的一些無關邏輯的存儲數據代碼就不貼了,這里我把代理服務器抓取到的數據存在了mysql,把自己的爬蟲程序爬到的數據存儲在了mongodb。

下面是自己爬取到的公眾號號的信息:

詳細Java批量獲取微信公眾號方法

 

詳細Java批量獲取微信公眾號方法

原文鏈接:https://www.cnblogs.com/luojiangwen/p/7943696.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产一级二级毛片 | 久久男 | 成人黄色在线免费观看 | 国产成人强伦免费视频网站 | 国产1区2 | 欧美一级做一a做片性视频 日韩黄色片免费看 | 一级免费特黄视频 | 色诱亚洲精品久久久久久 | 成人短视频在线观看 | 免费观看视频网站 | 毛片在线视频观看 | 欧美亚洲国产成人 | 国产精品高潮99久久久久久久 | v天堂在线视频 | 欧美成人国产va精品日本一级 | av电影网站在线观看 | 性欧美日本 | 97人操| 欧洲黄色一级视频 | 成年免费观看视频 | 成人mm视频在线观看 | 久草免费新视频 | 一级黄色影院 | 亚洲国产精品一区二区精品 | 日日草天天干 | 国产亚洲精品久久久久5区 男人天堂免费 | 欧美日韩亚洲国产 | 国产91免费看 | 毛毛片在线看 | 成人黄色在线免费观看 | 成人免费观看49www在线观看 | 久久亚洲成人网 | 国产69精品久久久久久 | 91视频久久| 九九爱视频 | 免费国产人成网站 | 国产免费人做人爱午夜视频 | 得得啪在线视频 | 在线成人一区二区 | 一区二区三区欧美日韩 | 中文字幕在线观看www |