摘要:我從年就開(kāi)始做微信公眾號(hào)內(nèi)容的批量采集,最開(kāi)始的目的是為了做一個(gè)的垃圾內(nèi)容網(wǎng)站。經(jīng)過(guò)實(shí)測(cè)的微信客戶端在批量采集過(guò)程中崩潰率高于安卓系統(tǒng)。在年年初的時(shí)候微信公眾號(hào)和微信文章開(kāi)始使用鏈接。
我從2014年就開(kāi)始做微信公眾號(hào)內(nèi)容的批量采集,最開(kāi)始的目的是為了做一個(gè)html5的垃圾內(nèi)容網(wǎng)站。當(dāng)時(shí)垃圾站采集到的微信公眾號(hào)的內(nèi)容很容易在公眾號(hào)里面?zhèn)鞑?。?dāng)時(shí)批量采集特別好做,采集入口是公眾號(hào)的歷史消息頁(yè)。這個(gè)入口到現(xiàn)在也是一樣,只不過(guò)越來(lái)越難采集了。采集的方式也更新?lián)Q代了好多個(gè)版本。后來(lái)在2015年html5垃圾站不做了,轉(zhuǎn)向?qū)⒉杉繕?biāo)定位在本地新聞資訊類(lèi)公眾號(hào),前端顯示做成了app。所以就形成了一個(gè)可以自動(dòng)采集公眾號(hào)內(nèi)容的新聞app。曾經(jīng)我一直擔(dān)心有一天微信技術(shù)升級(jí)之后無(wú)法采集內(nèi)容了,我的新聞app就失效了。但隨著微信不斷的技術(shù)升級(jí),采集方法也隨之升級(jí),反而使我越來(lái)越有信心。只要公眾號(hào)歷史消息頁(yè)存在,就能批量采集到內(nèi)容。所以今天決定將采集方法整理之后寫(xiě)下來(lái)。我的方法來(lái)源于許多同行的分享精神,所以我也會(huì)延續(xù)這個(gè)精神,將我的成果分享出來(lái)。
本篇文章將持續(xù)更新,你所看到的內(nèi)容將保證在看到的時(shí)間是可用的。
首先我們來(lái)看一個(gè)微信公眾號(hào)歷史消息頁(yè)面的鏈接地址:
http://mp.weixin.qq.com/mp/getmasssendmsg?__biz=MjM5MzczNjY2NA==&uin=NzM4MTk1ODgx&key=9ed31d4918c154c8e04cb95d0b28d07ae8eda2ba29a25f538d06adfa060e5d7d42a1427e8f9cfb6a4c3ecc0903a1a9ab87d1471e43705a8b04e1a796612405546f901ec1e4ea662122bb9235f4dfea4d&devicetype=android-17&version=26031c34&lang=zh_CN&nettype=WIFI&ascene=3&pass_ticket=iyVknv0cBEc1Z8oR4zVs%2BkLeRwYtW5bbtL4Tj9bm%2FwgjP%2BsobV6en3WohWUOllUU&wx_header=1
這里面有幾個(gè)參數(shù):
__biz;uin=;key=;devicetype=;version=;lang=;nettype=;ascene=;pass_ticket=;wx_header=;
其中重要的參數(shù)是:__biz;uin=;key=;pass_ticket=;這4個(gè)參數(shù)。
__biz是公眾號(hào)的一個(gè)類(lèi)似id的參數(shù),每個(gè)公眾號(hào)擁有一個(gè)微信的biz,目前極小概率會(huì)發(fā)生公眾號(hào)的biz會(huì)變化的事件;
剩下的3個(gè)參數(shù)是有關(guān)用戶的id和令牌票據(jù)之類(lèi)的意思,這3個(gè)參數(shù)的值只能通過(guò)微信的客戶端產(chǎn)生。所以我們想采集公眾號(hào)就必須通過(guò)一個(gè)微信客戶端app。在以前的微信版本中這3個(gè)參數(shù)還可以獲取一次之后在有效期之內(nèi)多個(gè)公眾號(hào)通用?,F(xiàn)在的版本已經(jīng)是每次訪問(wèn)一個(gè)公眾號(hào)都會(huì)更換參數(shù)值。
我現(xiàn)在所使用的方法只需要關(guān)注__biz這個(gè)參數(shù)就可以了。
我的采集系統(tǒng)由以下幾部分組成:
1、一個(gè)微信客戶端:可以是一臺(tái)手機(jī)安裝了微信的app,或者是用電腦中的安卓模擬器。經(jīng)過(guò)實(shí)測(cè)ios的微信客戶端在批量采集過(guò)程中崩潰率高于安卓系統(tǒng)。為了降低成本,我使用的是安卓模擬器。
2、一個(gè)微信個(gè)人號(hào):為了采集內(nèi)容不僅需要微信客戶端,還要有一個(gè)微信個(gè)人號(hào)專(zhuān)門(mén)用于采集,因?yàn)檫@個(gè)微信號(hào)就干不了其它事情了。
3、本地代理服務(wù)器系統(tǒng):目前使用的方法是通過(guò)Anyproxy代理服務(wù)器將公眾號(hào)歷史消息頁(yè)面中的文章列表發(fā)送到自己的服務(wù)器上。具體安裝設(shè)置方法在后面詳細(xì)介紹。
4、文章列表分析與入庫(kù)系統(tǒng):我用的是php語(yǔ)言編寫(xiě)的,后文將詳細(xì)介紹如何分析文章列表和建立采集隊(duì)列實(shí)現(xiàn)批量采集內(nèi)容。
步驟
一、安裝模擬器或使用手機(jī)安裝微信客戶端app,申請(qǐng)微信個(gè)人號(hào)并登錄到app上面。這一點(diǎn)就不過(guò)多介紹了,大家都會(huì)。
二、代理服務(wù)器系統(tǒng)安裝
目前我使用的是Anyproxy,AnyProxy 。這個(gè)軟件的特點(diǎn)是可以獲取到https鏈接的內(nèi)容。在2016年年初的時(shí)候微信公眾號(hào)和微信文章開(kāi)始使用https鏈接。并且Anyproxy可以通過(guò)修改rule配置實(shí)現(xiàn)向公眾號(hào)的頁(yè)面中插入腳本代碼。下面開(kāi)始介紹安裝與配置過(guò)程。
1、安裝 NodeJS
2、在命令行或者終端運(yùn)行 npm install -g anyproxy,mac系統(tǒng)需要加上sudo;
3、生成RootCA,https需要這個(gè)證書(shū):運(yùn)行命令sudo anyproxy --root(windows可能不需要sudo);
4、啟動(dòng)anyproxy運(yùn)行命令:sudo anyproxy -i;參數(shù)-i是解析HTTPS的意思;
5、安裝證書(shū),在手機(jī)或安卓模擬器中安裝證書(shū):
方法一: 啟動(dòng)anyproxy,瀏覽器打開(kāi) http://localhost:8002/fetchCr... ,能獲取rootCA.crt文件
方法二:?jiǎn)?dòng)anyproxy,http://localhost:8002/qr_root 可以獲取證書(shū)路徑的二維碼,移動(dòng)端安裝時(shí)會(huì)比較便捷
建議通過(guò)二維碼將證書(shū)安裝到手機(jī)中。
6、設(shè)置代理:安卓模擬器的代理服務(wù)器地址是wifi鏈接的網(wǎng)關(guān),可以通過(guò)吧dhcp設(shè)置為靜態(tài)后看到網(wǎng)關(guān)地址,看完后別忘了再設(shè)置為自動(dòng)。手機(jī)中的代理服務(wù)器地址就是運(yùn)行anyproxy的電腦的ip地址。代理服務(wù)器默認(rèn)端口是8001;
現(xiàn)在打開(kāi)微信,點(diǎn)擊到任意一個(gè)公眾號(hào)歷史消息或文章中,在終端都可以看到響應(yīng)的代碼滾動(dòng)。如果沒(méi)有出現(xiàn),請(qǐng)檢查手機(jī)的代理設(shè)置是否正確。
現(xiàn)在打開(kāi)瀏覽器地址http://localhost:8002 可以看到anyproxy的web界面。從微信中點(diǎn)開(kāi)一個(gè)歷史消息頁(yè)面,然后再看瀏覽器的web界面,會(huì)滾動(dòng)出現(xiàn)歷史消息頁(yè)面的地址。
以/mp/getmasssendmsg開(kāi)頭的網(wǎng)址就是微信歷史消息頁(yè)面。左邊一個(gè)小鎖頭表示這個(gè)頁(yè)面是https加密的?,F(xiàn)在我們點(diǎn)擊一下這一行;
右邊如果出現(xiàn)了html的文件內(nèi)容則表示解密成功。如果沒(méi)有內(nèi)容,請(qǐng)檢查anyproxy的運(yùn)行模式是否有參數(shù)i,是否生成了ca證書(shū),手機(jī)是否正確安裝證書(shū)。
現(xiàn)在我們的手機(jī)中的所有內(nèi)容都已經(jīng)可以明文通過(guò)代理服務(wù)器了。下面我們要修改配置代理服務(wù)器,使公眾號(hào)內(nèi)容被獲取到。
一、找到配置文件:
mac系統(tǒng)中配置文件的位置在/usr/local/lib/node_modules/anyproxy/lib/;windows系統(tǒng)請(qǐng)?jiān)徫視簳r(shí)不知道。應(yīng)該可以根據(jù)類(lèi)似mac的文件夾地址找到這個(gè)目錄。
二、修改文件rule_default.js
找到replaceServerResDataAsync: function(req,res,serverResData,callback) 函數(shù)
修改函數(shù)內(nèi)容(請(qǐng)注意詳細(xì)閱讀注釋?zhuān)@里只是介紹原理,理解后根據(jù)自己的條件修改內(nèi)容):
replaceServerResDataAsync: function(req,res,serverResData,callback){ if(/mp/getmasssendmsg/i.test(req.url)){//當(dāng)鏈接地址為公眾號(hào)歷史消息頁(yè)面時(shí) try {//防止報(bào)錯(cuò)退出程序 var reg = /msgList = (.*?); /;//定義歷史消息正則匹配規(guī)則 var ret = reg.exec(serverResData.toString());//轉(zhuǎn)換變量為string HttpPost(ret[1],req.url,"getMsgJson.php");//這個(gè)函數(shù)是后文定義的,將匹配到的歷史消息json發(fā)送到自己的服務(wù)器 var http = require("http"); http.get("http://xxx.com/getWxHis.php", function(res) {//這個(gè)地址是自己服務(wù)器上的一個(gè)程序,目的是為了獲取到下一個(gè)鏈接地址,將地址放在一個(gè)js腳本中,將頁(yè)面自動(dòng)跳轉(zhuǎn)到下一頁(yè)。后文將介紹getWxHis.php的原理。 res.on("data", function(chunk){ callback(chunk+serverResData);//將返回的代碼插入到歷史消息頁(yè)面中,并返回顯示出來(lái) }) }); }catch(e){//如果上面的正則沒(méi)有匹配到,那么這個(gè)頁(yè)面內(nèi)容可能是公眾號(hào)歷史消息頁(yè)面向下翻動(dòng)的第二頁(yè),因?yàn)闅v史消息第一頁(yè)是html格式的,第二頁(yè)就是json格式的。 try { var json = JSON.parse(serverResData.toString()); if (json.general_msg_list != []) { HttpPost(json.general_msg_list,req.url,"getMsgJson.php");//這個(gè)函數(shù)和上面的一樣是后文定義的,將第二頁(yè)歷史消息的json發(fā)送到自己的服務(wù)器 } }catch(e){ console.log(e);//錯(cuò)誤捕捉 } callback(serverResData);//直接返回第二頁(yè)json內(nèi)容 } }else if(/mp/getappmsgext/i.test(req.url)){//當(dāng)鏈接地址為公眾號(hào)文章閱讀量和點(diǎn)贊量時(shí) try { HttpPost(serverResData,req.url,"getMsgExt.php");//函數(shù)是后文定義的,功能是將文章閱讀量點(diǎn)贊量的json發(fā)送到服務(wù)器 }catch(e){ } callback(serverResData); }else if(/s?__biz/i.test(req.url) || /mp/rumor/i.test(req.url)){//當(dāng)鏈接地址為公眾號(hào)文章時(shí)(rumor這個(gè)地址是公眾號(hào)文章被辟謠了) try { var http = require("http"); http.get("http://xxx.com/getWxPost.php", function(res) {//這個(gè)地址是自己服務(wù)器上的另一個(gè)程序,目的是為了獲取到下一個(gè)鏈接地址,將地址放在一個(gè)js腳本中,將頁(yè)面自動(dòng)跳轉(zhuǎn)到下一頁(yè)。后文將介紹getWxPost.php的原理。 res.on("data", function(chunk){ callback(chunk+serverResData); }) }); }catch(e){ callback(serverResData); } }else{ callback(serverResData); } },
上面這段代碼是利用anyproxy可以修改返回頁(yè)面內(nèi)容的功能,向頁(yè)面注入腳本,和將頁(yè)面內(nèi)容發(fā)送到服務(wù)器上。使用這個(gè)原理來(lái)批量采集公眾號(hào)內(nèi)容和閱讀量。這段腳本中自定義了一個(gè)函數(shù),下面詳細(xì)介紹:
在rule_default.js文件末尾添加以下代碼:
function HttpPost(str,url,path) {//將json發(fā)送到服務(wù)器,str為json內(nèi)容,url為歷史消息頁(yè)面地址,path是接收程序的路徑和文件名 var http = require("http"); var data = { str: encodeURIComponent(str), url: encodeURIComponent(url) }; content = require("querystring").stringify(data); var options = { method: "POST", host: "www.xxx.com",//注意沒(méi)有http://,這是服務(wù)器的域名。 port: 80, path: path,//接收程序的路徑和文件名 headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Content-Length": content.length } }; var req = http.request(options, function (res) { res.setEncoding("utf8"); res.on("data", function (chunk) { console.log("BODY: " + chunk); }); }); req.on("error", function (e) { console.log("problem with request: " + e.message); }); req.write(content); req.end(); }
上面就是rule規(guī)則修改的主要部分,需要將json內(nèi)容發(fā)送到自己的服務(wù)器,還要從服務(wù)器獲取到下一頁(yè)的跳轉(zhuǎn)地址。這就涉及到了四個(gè)php文件:getMsgJson.php、getMsgExt.php、getWxHis.php、getWxPost.php
在詳細(xì)介紹這4個(gè)php文件之前,為了提高采集系統(tǒng)性能和降低崩潰率,我們還可以進(jìn)行一些修改:
安卓模擬器經(jīng)常會(huì)訪問(wèn)一些http://google.com的地址,這樣會(huì)導(dǎo)致anyproxy死機(jī),找到函數(shù)replaceRequestOption : function(req,option),修改函數(shù)內(nèi)容:
replaceRequestOption : function(req,option){ var newOption = option; if(/google/i.test(newOption.headers.host)){ newOption.hostname = "www.baidu.com"; newOption.port = "80"; } return newOption; },
以上就是針對(duì)anyproxy的rule文件的修改配置,配置修改完成之后,重新啟動(dòng)anyproxy。mac系統(tǒng)里按control+c中斷程序,再輸入命令sudo anyproxy -i啟動(dòng);如果啟動(dòng)報(bào)錯(cuò),可能是程序沒(méi)有退出干凈,端口被占用。這時(shí)輸入命令ps -a查看占用的pid,再輸入命令“kill -9 pid”這里將pid替換成查詢到的pid號(hào)碼。殺死進(jìn)程之后就可以啟動(dòng)anyproxy了。還是那句話windows的命令請(qǐng)?jiān)徫也惶煜ぁ?/p>
接下來(lái)詳細(xì)介紹服務(wù)器上接收程序的設(shè)計(jì)原理:
(以下代碼并不是直接可以用的,只是介紹原理,其中一部分需要根據(jù)自己的服務(wù)器數(shù)據(jù)庫(kù)框架進(jìn)行編寫(xiě))
1、getMsgJson.php:這個(gè)程序負(fù)責(zé)接收歷史消息的json并解析后存入數(shù)據(jù)庫(kù)
$str = $_POST["str"]; $url = $_POST["url"];//先獲取到兩個(gè)POST變量 //先針對(duì)url參數(shù)進(jìn)行操作 parse_str(parse_url(htmlspecialchars_decode(urldecode($url)),PHP_URL_QUERY ),$query);//解析url地址 $biz = $query["__biz"];//得到公眾號(hào)的biz //接下來(lái)進(jìn)行以下操作 //從數(shù)據(jù)庫(kù)中查詢biz是否已經(jīng)存在,如果不存在則插入,這代表著我們新添加了一個(gè)采集目標(biāo)公眾號(hào)。 //再解析str變量 $json = json_decode($str,true);//首先進(jìn)行json_decode if(!$json){ $json = json_decode(htmlspecialchars_decode($result),true);//如果不成功,就增加一步htmlspecialchars_decode } foreach($json["list"] as $k=>$v){ $type = $v["comm_msg_info"]["type"]; if($type==49){//type=49代表是圖文消息 $content_url = str_replace("", "", htmlspecialchars_decode($v["app_msg_ext_info"]["content_url"]));//獲得圖文消息的鏈接地址 $is_multi = $v["app_msg_ext_info"]["is_multi"];//是否是多圖文消息 $datetime = $v["comm_msg_info"]["datetime"];//圖文消息發(fā)送時(shí)間 //在這里將圖文消息鏈接地址插入到采集隊(duì)列庫(kù)中(隊(duì)列庫(kù)將在后文介紹,主要目的是建立一個(gè)批量采集隊(duì)列,另一個(gè)程序?qū)⒏鶕?jù)隊(duì)列安排下一個(gè)采集的公眾號(hào)或者文章內(nèi)容) //在這里根據(jù)$content_url從數(shù)據(jù)庫(kù)中判斷一下是否重復(fù) if("數(shù)據(jù)庫(kù)中不存在相同的$content_url") { $field_id = $v["app_msg_ext_info"]["fileid"];//一個(gè)微信給的id,每條文章唯一不重復(fù) $title = $v["app_msg_ext_info"]["title"];//文章標(biāo)題 $title_encode = urlencode(str_replace(" ", "", $title));//建議將標(biāo)題進(jìn)行編碼,這樣就可以存儲(chǔ)emoji特殊符號(hào)了 $digest = $v["app_msg_ext_info"]["digest"];//文章摘要 $source_url = str_replace("", "", htmlspecialchars_decode($v["app_msg_ext_info"]["source_url"]));//閱讀原文的鏈接 $cover = str_replace("", "", htmlspecialchars_decode($v["app_msg_ext_info"]["cover"]));//封面圖片 $is_top = 1;//標(biāo)記一下是頭條內(nèi)容 //現(xiàn)在存入數(shù)據(jù)庫(kù) echo "頭條標(biāo)題:".$title.$lastId." ";//這個(gè)echo可以顯示在anyproxy的終端里 } if($is_multi==1){//如果是多圖文消息 foreach($v["app_msg_ext_info"]["multi_app_msg_item_list"] as $kk=>$vv){//循環(huán)后面的圖文消息 $content_url = str_replace("","",htmlspecialchars_decode($vv["content_url"]));//圖文消息鏈接地址 //這里再次根據(jù)$content_url判斷一下數(shù)據(jù)庫(kù)中是否重復(fù)以免出錯(cuò) if("數(shù)據(jù)庫(kù)中不存在相同的$content_url"){ //在這里將圖文消息鏈接地址插入到采集隊(duì)列庫(kù)中(隊(duì)列庫(kù)將在后文介紹,主要目的是建立一個(gè)批量采集隊(duì)列,另一個(gè)程序?qū)⒏鶕?jù)隊(duì)列安排下一個(gè)采集的公眾號(hào)或者文章內(nèi)容) $title = $vv["title"];//文章標(biāo)題 $field_id = $vv["fileid"];//一個(gè)微信給的id,每條文章唯一不重復(fù) $title_encode = urlencode(str_replace(" ","",$title));//建議將標(biāo)題進(jìn)行編碼,這樣就可以存儲(chǔ)emoji特殊符號(hào)了 $digest = htmlspecialchars($vv["digest"]);//文章摘要 $source_url = str_replace("","",htmlspecialchars_decode($vv["source_url"]));//閱讀原文的鏈接 //$cover = getCover(str_replace("","",htmlspecialchars_decode($vv["cover"]))); $cover = str_replace("","",htmlspecialchars_decode($vv["cover"]));//封面圖片 //現(xiàn)在存入數(shù)據(jù)庫(kù) echo "標(biāo)題:".$title.$lastId." "; } } } } } ?>
再次強(qiáng)調(diào)代碼只是原理,其中一部分注視的代碼要自己編寫(xiě)。
2、getMsgExt.php獲取文章閱讀量和點(diǎn)贊量的程序
$str = $_POST["str"]; $url = $_POST["url"];//先獲取到兩個(gè)POST變量 //先針對(duì)url參數(shù)進(jìn)行操作 parse_str(parse_url(htmlspecialchars_decode(urldecode($url)),PHP_URL_QUERY ),$query);//解析url地址 $biz = $query["__biz"];//得到公眾號(hào)的biz $sn = $query["sn"]; //再解析str變量 $json = json_decode($str,true);//進(jìn)行json_decode //$sql = "select * from `文章表` where `biz`="".$biz."" and `content_url` like "%".$sn."%"" limit 0,1; //根據(jù)biz和sn找到對(duì)應(yīng)的文章 $read_num = $json["appmsgstat"]["read_num"];//閱讀量 $like_num = $json["appmsgstat"]["like_num"];//點(diǎn)贊量 //在這里同樣根據(jù)biz和sn在采集隊(duì)列表中刪除對(duì)應(yīng)的文章,代表這篇文章可以移出采集隊(duì)列了 //然后將閱讀量和點(diǎn)贊量更新到文章表中。 exit(json_encode($msg));//可以顯示在anyproxy的終端里 ?>
3、getWxHis.php、getWxPost.php兩個(gè)程序比較類(lèi)似,一起介紹
//getWxHis.php 當(dāng)前頁(yè)面為公眾號(hào)歷史消息時(shí),讀取這個(gè)程序 //在采集隊(duì)列表中有一個(gè)load字段,當(dāng)值等于1時(shí)代表正在被讀取 //首先刪除采集隊(duì)列表中l(wèi)oad=1的行 //然后從隊(duì)列表中任意select一行 if("隊(duì)列表為空"){ //隊(duì)列表如果空了,就從存儲(chǔ)公眾號(hào)biz的表中取得一個(gè)biz,這里我在公眾號(hào)表中設(shè)置了一個(gè)采集時(shí)間的time字段,按照正序排列之后,就得到時(shí)間戳最小的一個(gè)公眾號(hào)記錄,并取得它的biz $url = "http://mp.weixin.qq.com/mp/getmasssendmsg?__biz=".$biz."#wechat_webview_type=1&wechat_redirect";//拼接公眾號(hào)歷史消息url地址 //更新剛才提到的公眾號(hào)表中的采集時(shí)間time字段為當(dāng)前時(shí)間戳。 }else{ //取得當(dāng)前這一行的content_url字段 $url = $content_url; //將load字段update為1 } echo "";//將下一個(gè)將要跳轉(zhuǎn)的$url變成js腳本,由anyproxy注入到微信頁(yè)面中。 ?> //getWxPost.php 當(dāng)前頁(yè)面為公眾號(hào)文章頁(yè)面時(shí),讀取這個(gè)程序 //首先刪除采集隊(duì)列表中l(wèi)oad=1的行 //然后從隊(duì)列表中按照“order by id asc”選擇多行(注意這一行和上面的程序不一樣) if(!empty("隊(duì)列表") && count("隊(duì)列表中的行數(shù)")>1){//(注意這一行和上面的程序不一樣) //取得第0行的content_url字段 $url = $content_url; //將第0行的load字段update為1 }else{ //隊(duì)列表還剩下最后一條時(shí),就從存儲(chǔ)公眾號(hào)biz的表中取得一個(gè)biz,這里我在公眾號(hào)表中設(shè)置了一個(gè)采集時(shí)間的time字段,按照正序排列之后,就得到時(shí)間戳最小的一個(gè)公眾號(hào)記錄,并取得它的biz $url = "http://mp.weixin.qq.com/mp/getmasssendmsg?__biz=".$biz."#wechat_webview_type=1&wechat_redirect";//拼接公眾號(hào)歷史消息url地址 //更新剛才提到的公眾號(hào)表中的采集時(shí)間time字段為當(dāng)前時(shí)間戳。 } echo "";//將下一個(gè)將要跳轉(zhuǎn)的$url變成js腳本,由anyproxy注入到微信頁(yè)面中。 ?>
這兩個(gè)程序的微小差別是因?yàn)楫?dāng)讀取公眾號(hào)歷史消息頁(yè)面時(shí),anyproxy會(huì)同時(shí)做兩件事,第一是將歷史消息的json發(fā)送到服務(wù)器,第二是獲取到下一頁(yè)的鏈接地址。但是這兩個(gè)操作是存在時(shí)間差的,第一次讀取下一頁(yè)地址時(shí)候本來(lái)應(yīng)該是得到當(dāng)前這個(gè)公眾號(hào)文章的第一條鏈接地址,但是這時(shí)候歷史消息的json還沒(méi)有發(fā)送到服務(wù)器,所以只能得到第二個(gè)公眾號(hào)的歷史消息頁(yè)面。在讀取第二個(gè)公眾號(hào)歷史消息頁(yè)面之后得到的下一頁(yè)地址則是第一個(gè)公眾號(hào)的第一篇文章的地址。當(dāng)隊(duì)列還剩下一條記錄時(shí),就需要再去取得下一個(gè)公眾號(hào)的鏈接地址,否則如果當(dāng)隊(duì)列空了再去取得下一個(gè)公眾號(hào)的鏈接地址,就會(huì)循環(huán)到上面提到的第一次讀取時(shí)的情況,這樣就會(huì)出現(xiàn)兩個(gè)公眾號(hào)歷史消息列表和文章采集穿插進(jìn)行的情況。
剛才這4個(gè)PHP程序提到了幾個(gè)數(shù)據(jù)表,下面再講一下數(shù)據(jù)表如何設(shè)計(jì)。這里只介紹一些主要字段,現(xiàn)實(shí)應(yīng)用中還會(huì)根據(jù)自己程序的不同添加上其它有必要的字段。
1、微信公眾號(hào)表
CREATE TABLE `weixin` ( `id` int(11) NOT NULL AUTO_INCREMENT, `biz` varchar(255) DEFAULT "" COMMENT "公眾號(hào)唯一標(biāo)識(shí)biz", `collect` int(11) DEFAULT "1" COMMENT "記錄采集時(shí)間的時(shí)間戳", PRIMARY KEY (`id`) ) ;
2、微信文章表
CREATE TABLE `post` ( `id` int(11) NOT NULL AUTO_INCREMENT, `biz` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT "文章對(duì)應(yīng)的公眾號(hào)biz", `field_id` int(11) NOT NULL COMMENT "微信定義的一個(gè)id,每條文章唯一", `title` varchar(255) NOT NULL DEFAULT "" COMMENT "文章標(biāo)題", `title_encode` text CHARACTER SET utf8 NOT NULL COMMENT "文章編碼,防止文章出現(xiàn)emoji", `digest` varchar(500) NOT NULL DEFAULT "" COMMENT "文章摘要", `content_url` varchar(500) CHARACTER SET utf8 NOT NULL COMMENT "文章地址", `source_url` varchar(500) CHARACTER SET utf8 NOT NULL COMMENT "閱讀原文地址", `cover` varchar(500) CHARACTER SET utf8 NOT NULL COMMENT "封面圖片", `is_multi` int(11) NOT NULL COMMENT "是否多圖文", `is_top` int(11) NOT NULL COMMENT "是否頭條", `datetime` int(11) NOT NULL COMMENT "文章時(shí)間戳", `readNum` int(11) NOT NULL DEFAULT "1" COMMENT "文章閱讀量", `likeNum` int(11) NOT NULL DEFAULT "0" COMMENT "文章點(diǎn)贊量", PRIMARY KEY (`id`) ) ;
3、采集隊(duì)列表
CREATE TABLE `tmplist` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `content_url` varchar(255) DEFAULT NULL COMMENT "文章地址", `load` int(11) DEFAULT "0" COMMENT "讀取中標(biāo)記", PRIMARY KEY (`id`), UNIQUE KEY `content_url` (`content_url`) ) ;
以上就是由微信客戶端、微信號(hào)、anyproxy代理服務(wù)器、PHP程序、mysql數(shù)據(jù)庫(kù)共同組成的微信公眾號(hào)文章批量自動(dòng)采集系統(tǒng)。
在接下來(lái)的文章中,還會(huì)再進(jìn)一步詳細(xì)介紹如何保存文章內(nèi)容,如何提高采集系統(tǒng)的穩(wěn)定性,以及其它我的系統(tǒng)運(yùn)行過(guò)程中得到的經(jīng)驗(yàn)。
非常希望大家能給予意見(jiàn)和交流,歡迎騷擾微信號(hào)cuijin。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/22184.html
摘要:要想實(shí)現(xiàn)微信公眾號(hào)文章的爬取,需要做兩部分系統(tǒng)處理。詳細(xì)實(shí)現(xiàn)步驟文章和源碼資源見(jiàn)個(gè)人博文微信公眾號(hào)文章采集之服務(wù)端數(shù)據(jù)采集 要想實(shí)現(xiàn)微信公眾號(hào)文章的爬取,需要做兩部分系統(tǒng)處理。 一、公眾號(hào)文章的自動(dòng)化瀏覽處理 一個(gè)是移動(dòng)端的公眾號(hào)文章自動(dòng)瀏覽實(shí)現(xiàn),逐個(gè)訪問(wèn)瀏覽公眾號(hào)的歷史文章,在瀏覽公眾號(hào)文章的時(shí)候會(huì)請(qǐng)求公眾號(hào)的文章鏈接地址,通過(guò)AnyProxy中間人代理解析工具,可以獲取到永久的文章...
摘要:本文轉(zhuǎn)載自微信公眾號(hào)賬號(hào),作者為海航生態(tài)科技技術(shù)研究院大數(shù)據(jù)開(kāi)發(fā)工程師高顏。文章介紹了海航生態(tài)科技輿情大數(shù)據(jù)平臺(tái)的容器化改造經(jīng)驗(yàn),包括初期技術(shù)架構(gòu)應(yīng)用容器化架構(gòu)遷移持續(xù)發(fā)布與部署。 本文轉(zhuǎn)載自微信公眾號(hào)Docker(賬號(hào):dockerone),作者為海航生態(tài)科技技術(shù)研究院大數(shù)據(jù)開(kāi)發(fā)工程師高顏。 文章介紹了海航生態(tài)科技輿情大數(shù)據(jù)平臺(tái)的容器化改造經(jīng)驗(yàn),包括初期技術(shù)架構(gòu)、應(yīng)用容器化、架構(gòu)遷...
摘要:再如通過(guò)處理流數(shù)據(jù)生成簡(jiǎn)單的報(bào)告,如五分鐘的窗口聚合數(shù)據(jù)平均值。復(fù)雜的事情還有在流數(shù)據(jù)中進(jìn)行數(shù)據(jù)多維度關(guān)聯(lián)聚合塞選,從而找到復(fù)雜事件中的根因。因?yàn)楦鞣N需求,也就造就了現(xiàn)在不斷出現(xiàn)實(shí)時(shí)計(jì)算框架,而下文我們將重磅介紹我們推薦的實(shí)時(shí)計(jì)算框架。 前言 先廣而告之,本文摘自本人《大數(shù)據(jù)重磅炸彈——實(shí)時(shí)計(jì)算框架 Flink》課程第二篇,內(nèi)容首發(fā)自我的知識(shí)星球,后面持續(xù)在星球里更新,這里做個(gè)預(yù)告,今...
摘要:擴(kuò)展庫(kù)還包括用于復(fù)雜事件處理,機(jī)器學(xué)習(xí),圖形處理和兼容性的專(zhuān)用代碼庫(kù)。事件時(shí)間機(jī)制使得那些事件無(wú)序到達(dá)甚至延遲到達(dá)的數(shù)據(jù)流能夠計(jì)算出精確的結(jié)果。負(fù)責(zé)接受用戶的程序代碼,然后創(chuàng)建數(shù)據(jù)流,將數(shù)據(jù)流提交給以便進(jìn)一步執(zhí)行。 showImg(https://segmentfault.com/img/remote/1460000016902812); 前言 Flink 是一種流式計(jì)算框架,為什么我...
閱讀 3121·2021-11-23 09:51
閱讀 3652·2021-10-13 09:39
閱讀 2539·2021-09-22 15:06
閱讀 912·2019-08-30 15:55
閱讀 3183·2019-08-30 15:44
閱讀 1809·2019-08-30 14:05
閱讀 3468·2019-08-29 15:24
閱讀 2388·2019-08-29 12:44