微信公眾號文章頁的分析與採集
我們還是從一個公眾號文章的連結地址開始看:
1、從微信右上角選單複製到的連結地址:
http://mp.weixin.qq.com/s/fF34bERZ0je_8RWEJjoZ5A
2、歷史訊息列表中獲取到的地址:
http://mp.weixin.qq.com/s?__biz=MjM5NDAwMTA2MA==&mid=2695729619&idx=1&sn=8be0b6bd0210cee0d492ebdf20f7371f&chksm=83d74818b4a0c10ef286b33bb7deb73226125f866ddb5b2781166066a69afef3705eabdb3b85&scene=4#wechat_redirect
3、完整的真實地址:
https://mp.weixin.qq.com/s?__biz=MjM5NDAwMTA2MA==&mid=2695729619&idx=1&sn=8be0b6bd0210cee0d492ebdf20f7371f&chksm=83d74818b4a0c10ef286b33bb7deb73226125f866ddb5b2781166066a69afef3705eabdb3b85&scene=37&key=c81d77271180a0e6ce32be2d9dcaa2a7436aeba2c1d47a20d02194d1c944a8286a8eded93495eeadd05da412bbfaa638a379750aeaa4cf5c00e4d7851c5710d9b9736b80e3c72770a57a515c23ff2400&ascene=3&uin=MzUyOTIyNQ%3D%3D&devicetype=iOS10.1.1&version=16050120&nettype=WIFI&fontScale=100&pass_ticket=FGRyGfXLPEa4AeOsIZu7KFJo6CiXOZex83Y5YBRglW4%3D&wx_header=1
以上這3個地址是同一篇文章的地址,在不同位置獲取到就得到了完全不同的3個結果。
和歷史訊息頁一樣,微信有一套自動補充引數的機制。第一個地址是複製連結得到的,看起來是一個偽裝的編碼。其實沒什麼用我們不做考慮了。第二個地址是通過前面文章介紹的方法,從歷史訊息的json文章列表中獲得到的連結地址,我們就是可以將這個地址儲存到資料庫中。之後就可以通過這個地址從伺服器獲取到文章內容。而第三個連結補充了引數之後,目的是為了讓文章頁面中的閱讀量js可以獲取到閱讀量點贊量的json結果而加上的引數。我們前面文章的方法中因為文章頁面被客戶端開啟顯示了出來,因為有了這些引數,文章頁面中的js就去自動獲取閱讀量了,所以我們才能通過代理服務獲取到這篇文章的閱讀量。
這篇文章的內容就是以通過本專欄前面文章介紹的方法已經獲取到了大量微信文章的基礎上,詳細研究如何獲取到文章內容和其它一些有用的資訊的方法。
(我的資料庫中儲存的文章列表,一部分欄位)
1、獲取文章原始碼:
通過php的函式file_get_content()就可以將文章原始碼讀取到變數中。微信文章的原始碼因為可以從瀏覽器中開啟所以我就不在這裡貼上了,以免浪費頁面空間。
<?
//$content_url 變數的值為文章地址
$html = file_get_contents($content_url);
?>
2、原始碼中有用的資訊:
1)原文內容:
原文內容是包含在一個<div id='js_content'></div>標籤中的,通過php程式碼獲取:
<?
preg_match_all("/id=\"js_content\">(.*)<script/iUs",$html,$content,PREG_PATTERN_ORDER);
$content = "<div id='js_content'>".$content[1][0];
?>
正則的開頭識別<div id='js_content'>,結尾識別<script/iUs,匹配到之後前面再補充一個<div id='js_content'>;我的正則匹配水平有限,只能寫成這樣的了。希望有高人能指點更好的正則匹配方法。
另外注意:這個匹配規則會可能在一段時間之後有變化。這篇文章會盡量保持更新。如果你根據我的文章製作了採集系統之後,當某一天失效了,別忘了回來再看看文章是否有更新。
2)內容處理:通過上面的方法我們獲得了文章內容的html,但是你將文章內容顯示出來之後就會發現,圖片和視訊不能正常顯示。因為這個html還需要一些加工:
首先是圖片,微信文章中的<img>標籤中的src屬性全部都用了data-src屬性代替。只有在顯示的時候才會被替換過來。所以我們也有兩個方案,將原始碼直接替換過來,或者用js在顯示時候再替換。下面我先介紹直接替換html的方法:
<?
//$content變數的值是前面獲取到的文章內容html
$content = str_replace("data-src","src",$content);
?>
然後是視訊,視訊的顯示不正常,經過長期測試後發現只要替換一個頁面地址就能解決,過程就不說了,直接說結果:
<?
//$content變數的值是前面獲取到的文章內容html
$content = str_replace("preview.html","player.html",$content);
?>
通過這兩個替換之後,文章內容html中的圖片和視訊就都正常了。
3) 公眾號相關資訊:
通過本專欄之前的文章,介紹了我們使用微信客戶端,任意開啟一個公眾號的歷史訊息頁之後。系統從資料庫中識別biz的值,發現數據庫中沒有記錄,就會插入一條新的紀錄。之後的採集佇列就會定期根據這個biz來獲取這個公眾號的歷史訊息列表。
但是我們只獲得了這個公眾號的biz,公眾號的名稱,頭像這兩個重要資訊還是沒有獲取到。主要原因是歷史訊息頁面中沒有這兩個資訊。但是我們可以從文章頁面中獲取到。
在微信文章頁面html的底部,有一些js的變數賦值的程式碼,通過正則匹配之後我們就可以獲得這兩個公眾號的資訊:
<?
//$html變數的值是前面獲取到的文章全部html
preg_match_all('/var nickname = \"(.*?)\";/si',$html,$m);
$nickname = $m[1][0];//公眾號暱稱
preg_match_all('/var round_head_img = \"(.*?)\";/si',$html,$m);
$head_img = $m[1][0];//公眾號頭像
?>
通過這兩個正則匹配,我們就能獲取到公眾號的頭像和暱稱,然後根據文章地址中的biz,可以儲存到對應的微訊號資料表中。
3、文章的儲存和處理
前面的程式碼已經將文章內容獲取到變數中了。如何儲存其實每個人也許都有自己的想法。我這裡介紹一下我的儲存內容的方法:
將文章內容的html以資料庫id為檔名儲存成html檔案,以biz欄位為目錄。
<?
$dir = "./".$biz."/";
$filename = $dir.$id.".html";
if(!is_dir($dir)) {
mkdir($cache_dir);
chmod($cache_dir,0777);
}
$file = fopen($filename, "w");
fwrite($file, $content);
fclose($file);
?>
以上程式碼是一個標準的php建立資料夾儲存檔案的程式碼,大家可以根據自己的實際情況安排儲存方法。
在這之後我們就可以在自己的伺服器上得到一個html檔案,內容就是公眾號的文章內容。我們可以從瀏覽器中開啟看一下。這時你也許會發現圖片防盜鏈了!無法正常顯示!包括資料庫中儲存的文章封面圖,公眾號的頭像都是防盜鏈的。
別急,這個問題很好解決,只需要將圖片也儲存到自己的伺服器,無非是將來會佔用自己的伺服器空間和頻寬。
圖片防盜鏈的原理是當圖片在網頁中顯示的時候,圖片伺服器會檢測到引用這張圖片的伺服器域名,當發現伺服器域名不包含http://qq.com或http://qpic.cn的時候就會被替換成防盜鏈圖片。
但是如果檢測不到引用頁面的域名就會正常顯示,所以我們通過php的函式file_get_content()就可以將圖片的二進位制程式碼獲取過來,然後根據自己的想法起個檔名儲存到自己的伺服器上。在這裡再介紹一個儲存圖片的方法,我目前使用了騰訊雲的“永珍優圖”,通過它們提供的api將圖片儲存到雲空間,這樣的好處是讀取圖片時直接在圖片的連結地址加上希望得到的圖片尺寸大小引數,就可以直接得到一張縮圖。比存在自己的伺服器方便得多。阿里雲也應該有同樣的產品,好像名叫物件儲存。
另外,我採集公眾號內容的目的是製作成一個新聞app,在app中將html程式碼顯示出來之後,因為app同樣沒有域名,防盜鏈伺服器也同樣不會認為圖片被盜鏈了。這樣就可以直接顯示圖片出來。
以上就是我總結的公眾號文章內容的採集與儲存方法,希望能夠幫到你。在下一篇文章中,我將介紹anyproxy的進階使用方法,可以進一步降低採集程式的崩潰率,提高採集效率。
非常希望大家能給予意見和交流,歡迎騷擾微訊號cuijin。