此文章撰寫于國慶假期,以此紀(jì)念,。祝大家萬事大吉,心想事成,家和萬事興!國慶快樂! 微信公眾號(hào)爬蟲的基本原理網(wǎng)上關(guān)于爬蟲的教程多如牛毛,但很少有看到微信公眾號(hào)爬蟲教程,要有也是基于搜狗微信的,不過搜狗提供的數(shù)據(jù)有諸多弊端,比如文章鏈接是臨時(shí)的,文章沒有閱讀量等指標(biāo),所以我想寫一個(gè)比較系統(tǒng)的關(guān)于如何通過手機(jī)客戶端利用 Python 爬微信公眾號(hào)文章的教程,并對(duì)公眾號(hào)文章做數(shù)據(jù)分析,為更好的運(yùn)營公眾號(hào)提供決策,。 爬蟲的基本原理所謂爬蟲就是一個(gè)自動(dòng)化數(shù)據(jù)采集工具,你只要告訴它要采集哪些數(shù)據(jù),丟給它一個(gè) URL,就能自動(dòng)地抓取數(shù)據(jù)了。其背后的基本原理就是爬蟲程序向目標(biāo)服務(wù)器發(fā)起 HTTP 請(qǐng)求,然后目標(biāo)服務(wù)器返回響應(yīng)結(jié)果,爬蟲客戶端收到響應(yīng)并從中提取數(shù)據(jù),再進(jìn)行數(shù)據(jù)清洗,、數(shù)據(jù)存儲(chǔ)工作,。 爬蟲的基本流程爬蟲流程也是一個(gè) HTTP 請(qǐng)求的過程,以瀏覽器訪問一個(gè)網(wǎng)址為例,從用戶輸入 URL 開始,客戶端通過 DNS 解析查詢到目標(biāo)服務(wù)器的 IP 地址,然后與之建立 TCP 連接,連接成功后,瀏覽器構(gòu)造一個(gè) HTTP 請(qǐng)求發(fā)送給服務(wù)器,服務(wù)器收到請(qǐng)求之后,從數(shù)據(jù)庫查到相應(yīng)的數(shù)據(jù)并封裝成一個(gè) HTTP 響應(yīng),然后將響應(yīng)結(jié)果返回給瀏覽器,瀏覽器對(duì)響應(yīng)內(nèi)容進(jìn)行數(shù)據(jù)解析、提取,、渲染并最終展示在你面前,。 HTTP 協(xié)議的請(qǐng)求和響應(yīng)都必須遵循固定的格式,只有遵循統(tǒng)一的 HTTP 請(qǐng)求格式,服務(wù)器才能正確解析不同客戶端發(fā)的請(qǐng)求,同樣地,服務(wù)器遵循統(tǒng)一的響應(yīng)格式,客戶端才得以正確解析不同網(wǎng)站發(fā)過來的響應(yīng)。 HTTP 請(qǐng)求格式HTTP 請(qǐng)求由請(qǐng)求行,、請(qǐng)求頭,、空行、請(qǐng)求體組成,。 ?請(qǐng)求行由三部分組成:
請(qǐng)求頭是客戶端向服務(wù)器發(fā)送請(qǐng)求的補(bǔ)充說明,比如 User-Agent 向服務(wù)器說明客戶端的身份。 請(qǐng)求體是客戶端向服務(wù)器提交的數(shù)據(jù),比如用戶登錄時(shí)需要提高的賬號(hào)密碼信息,。請(qǐng)求頭與請(qǐng)求體之間用空行隔開,。請(qǐng)求體并不是所有的請(qǐng)求都有的,比如一般的GET都不會(huì)帶有請(qǐng)求體,。 上圖就是瀏覽器登錄豆瓣時(shí)向服務(wù)器發(fā)送的HTTP POST 請(qǐng)求,請(qǐng)求體中指定了用戶名和密碼。 HTTP 響應(yīng)格式HTTP 響應(yīng)格式與請(qǐng)求的格式很相似,也是由響應(yīng)行,、響應(yīng)頭,、空行、響應(yīng)體組成,。 響應(yīng)行也包含三部分,分別是服務(wù)端的 HTTP 版本號(hào),、響應(yīng)狀態(tài)碼、狀態(tài)說明,響應(yīng)狀態(tài)碼常見有 200,、400,、404、500,、502,、304 等等,一般以 2 開頭的表示服務(wù)器正常響應(yīng)了客戶端請(qǐng)求,4 開頭表示客戶端的請(qǐng)求有問題,5 開頭表示服務(wù)器出錯(cuò)了,沒法正確處理客戶端請(qǐng)求。狀態(tài)碼說明就是對(duì)該狀態(tài)碼的一個(gè)簡短描述,。 第二部分就是響應(yīng)頭,響應(yīng)頭與請(qǐng)求頭對(duì)應(yīng),是服務(wù)器對(duì)該響應(yīng)的一些附加說明,比如響應(yīng)內(nèi)容的格式是什么,響應(yīng)內(nèi)容的長度有多少,、什么時(shí)間返回給客戶端的、甚至還有一些 Cookie 信息也會(huì)放在響應(yīng)頭里面,。 第三部分是響應(yīng)體,它才是真正的響應(yīng)數(shù)據(jù),這些數(shù)據(jù)其實(shí)就是網(wǎng)頁的 HTML 源代碼,。 使用 Requests 實(shí)現(xiàn)一個(gè)簡單網(wǎng)頁爬蟲Python 提供了非常多工具去實(shí)現(xiàn) HTTP 請(qǐng)求,但第三方開源庫提供的功能更豐富,你無需從 socket 通信開始寫,比如使用Pyton內(nèi)建模塊?
發(fā)起請(qǐng)求前首先要構(gòu)建請(qǐng)求對(duì)象 Request,指定 url 地址、請(qǐng)求方法,、請(qǐng)求頭,這里的請(qǐng)求體 data 為空,因?yàn)槟悴恍枰峤粩?shù)據(jù)給服務(wù)器,所以你也可以不指定,。urlopen 函數(shù)會(huì)自動(dòng)與目標(biāo)服務(wù)器建立連接,發(fā)送 HTTP 請(qǐng)求,該函數(shù)的返回值是一個(gè)響應(yīng)對(duì)象 Response,里面有響應(yīng)頭信息,響應(yīng)體,狀態(tài)碼之類的屬性。 但是,Python 提供的這個(gè)內(nèi)建模塊過于低級(jí),需要寫很多代碼,使用簡單爬蟲可以考慮 Requests,Requests 在GitHub 有近30k的Star,是一個(gè)很Pythonic的框架,。先來簡單熟悉一下這個(gè)框架的使用方式 安裝 requests
GET 請(qǐng)求
POST 請(qǐng)求
自定義請(qǐng)求頭這個(gè)經(jīng)常會(huì)用到,服務(wù)器反爬蟲機(jī)制會(huì)判斷客戶端請(qǐng)求頭中的User-Agent是否來源于真實(shí)瀏覽器,所以,我們使用Requests經(jīng)常會(huì)指定UA偽裝成瀏覽器發(fā)起請(qǐng)求
參數(shù)傳遞很多時(shí)候URL后面會(huì)有一串很長的參數(shù),為了提高可讀性,requests 支持將參數(shù)抽離出來作為方法的參數(shù)(params)傳遞過去,而無需附在 URL 后面,例如請(qǐng)求 url http:///get?key=val ,可使用
指定CookieCookie 是web瀏覽器登錄網(wǎng)站的憑證,雖然 Cookie 也是請(qǐng)求頭的一部分,我們可以從中剝離出來,使用 Cookie 參數(shù)指定
設(shè)置超時(shí)當(dāng)發(fā)起一個(gè)請(qǐng)求遇到服務(wù)器響應(yīng)非常緩慢而你又不希望等待太久時(shí),可以指定 timeout 來設(shè)置請(qǐng)求超時(shí)時(shí)間,單位是秒,超過該時(shí)間還沒有連接服務(wù)器成功時(shí),請(qǐng)求將強(qiáng)行終止,。
設(shè)置代理一段時(shí)間內(nèi)發(fā)送的請(qǐng)求太多容易被服務(wù)器判定為爬蟲,所以很多時(shí)候我們使用代理IP來偽裝客戶端的真實(shí)IP。
Session如果想和服務(wù)器一直保持登錄(會(huì)話)狀態(tài),而不必每次都指定 cookies,那么可以使用 session,Session 提供的API和 requests 是一樣的,。
小試牛刀現(xiàn)在我們使用Requests完成一個(gè)爬取知乎專欄用戶關(guān)注列表的簡單爬蟲為例,找到任意一個(gè)專欄,打開它的關(guān)注列表,。用 Chrome 找到獲取粉絲列表的請(qǐng)求地址:https://www.zhihu.com/api/v4/columns/pythoneer/followers?include=data%5B%2A%5D.follower_count%2Cgender%2Cis_followed%2Cis_following&limit=10&offset=20。 我是怎么找到的?就是逐個(gè)點(diǎn)擊左側(cè)的請(qǐng)求,觀察右邊是否有數(shù)據(jù)出現(xiàn),那些以? 現(xiàn)在我們用 Requests 模擬瀏覽器發(fā)送請(qǐng)求給服務(wù)器,寫程序前,我們要先分析出這個(gè)請(qǐng)求是怎么構(gòu)成的,請(qǐng)求URL是什么?請(qǐng)求頭有哪些?查詢參數(shù)有哪些?只有清楚了這些,你才好動(dòng)手寫代碼,掌握分析方法很重要,否則一頭霧水,。 回到前面那個(gè)URL,我們發(fā)現(xiàn)這個(gè)URL是獲取粉絲列表的接口,然后再來詳細(xì)分析一下這個(gè)請(qǐng)求是怎么構(gòu)成的。
利用這些請(qǐng)求數(shù)據(jù)我們就可以用requests這個(gè)庫來構(gòu)建一個(gè)請(qǐng)求,通過Python代碼來抓取這些數(shù)據(jù),。
這就是一個(gè)最簡單的基于 Requests 的單線程知乎專欄粉絲列表的爬蟲,requests 非常靈活,請(qǐng)求頭、請(qǐng)求參數(shù),、Cookie 信息都可以直接指定在請(qǐng)求方法中,返回值 response 如果是 json 格式可以直接調(diào)用json()方法返回 python 對(duì)象。關(guān)于 Requests 的更多使用方法可以參考官方文檔:Requests: HTTP for Humans? — Requests 2.26.0 documentation 使用 Fiddler 抓包分析公眾號(hào)請(qǐng)求過程上一節(jié)我們熟悉了 Requests 基本使用方法,配合 Chrome 瀏覽器實(shí)現(xiàn)了一個(gè)簡單爬蟲,但因?yàn)槲⑿殴娞?hào)的封閉性,微信公眾平臺(tái)并沒有對(duì)外提供 Web 端入口,只能通過手機(jī)客戶端接收,、查看公眾號(hào)文章,所以,為了窺探到公眾號(hào)背后的網(wǎng)絡(luò)請(qǐng)求,我們需要借以代理工具的輔助,。 HTTP代理工具又稱為抓包工具,主流的抓包工具 Windows 平臺(tái)有 Fiddler,macOS 有 Charles,阿里開源了一款工具叫 AnyProxy,。它們的基本原理都是類似的,就是通過在手機(jī)客戶端設(shè)置好代理IP和端口,客戶端所有的 HTTP、HTTPS 請(qǐng)求就會(huì)經(jīng)過代理工具,在代理工具中就可以清晰地看到每個(gè)請(qǐng)求的細(xì)節(jié),然后可以分析出每個(gè)請(qǐng)求是如何構(gòu)造的,弄清楚這些之后,我們就可以用 Python 模擬發(fā)起請(qǐng)求,進(jìn)而得到我們想要的數(shù)據(jù),。 Fiddler 下載地址是?Download Fiddler Web Debugging Tool for Free by Telerik,安裝包就 4M 多,在配置之前,首先要確保你的手機(jī)和電腦在同一個(gè)局域網(wǎng),如果不在同一個(gè)局域網(wǎng),你可以買個(gè)隨身WiFi,在你電腦上搭建一個(gè)極簡無線路由器,。安裝過程一路點(diǎn)擊下一步完成就可以了。 Fiddler 配置選擇?Tools > Fiddler Options > Connections Fiddler 默認(rèn)的端口是使用 8888,如果該端口已經(jīng)被其它程序占用了,你需要手動(dòng)更改,勾選 Allow remote computers to connect,其它的選擇默認(rèn)配置就好,配置更新后記得重啟 Fiddler,。一定要重啟 Fiddler,否則代理無效,。 接下來你需要配置手機(jī),我們以 Android 設(shè)備為例,現(xiàn)在假設(shè)你的手機(jī)和電腦已經(jīng)在同一個(gè)局域網(wǎng)(只要連的是同一個(gè)路由器就在同局域網(wǎng)內(nèi)),找到電腦的 IP 地址,在 Fiddler 右上角有個(gè) Online 圖標(biāo),鼠標(biāo)移過去就能看到IP了,你也可以在CMD窗口使用? Android 手機(jī)代理配置進(jìn)入手機(jī)的 WLAN 設(shè)置,選擇當(dāng)前所在局域網(wǎng)的 WiFi 鏈接,設(shè)置代理服務(wù)器的 IP 和端口,我這是以小米設(shè)備為例,其它 Android 手機(jī)的配置過程大同小異。 測試代理有沒有設(shè)置成功可以在手機(jī)瀏覽器訪問你配置的地址:http://192.168.31.236:8888/ 會(huì)顯示 Fiddler 的回顯頁面,說明配置成功,。 現(xiàn)在你打開任意一個(gè)HTTP協(xié)議的網(wǎng)站都能看到請(qǐng)求會(huì)出現(xiàn)在 Fiddler 窗口,但是 HTTPS 的請(qǐng)求并沒有出現(xiàn)在 Fiddler 中,其實(shí)還差一個(gè)步驟,需要在 Fiddler 中激活 HTTPS 抓取設(shè)置,。在 Fiddler 選擇?Tools > Fiddler Options > HTTPS > Decrypt HTTPS traffic, 重啟 Fiddler。 為了能夠讓 Fiddler 截取 HTTPS 請(qǐng)求,客戶端都需要安裝且信任 Fiddler 生成的 CA 證書,否則會(huì)出現(xiàn)“網(wǎng)絡(luò)出錯(cuò),輕觸屏幕重新加載:-1200”的錯(cuò)誤,。在瀏覽器打開 Fiddler 回顯頁面 http://192.168.31.236:8888/ 下載?FiddlerRoot certificate,下載并安裝證書,并驗(yàn)證通過,。 iOS下載安裝完成之后還要從?設(shè)置->通用->關(guān)于本機(jī)->證書信任設(shè)置?中把 Fiddler 證書的開關(guān)打開 Android 手機(jī)下載保存證書后從系統(tǒng)設(shè)置里面找到系統(tǒng)安全,從SD卡安裝證書,如果沒有安裝證書,打開微信公眾號(hào)的時(shí)候會(huì)彈出警告。 至此,所有的配置都完成了,現(xiàn)在打開微信隨便選擇一個(gè)公眾號(hào),查看公眾號(hào)的所有歷史文章列表,。微信在2018年6月份對(duì) iOS 版本的微信以及部分 Android 版微信針對(duì)公眾號(hào)進(jìn)行了大幅調(diào)整,改為現(xiàn)在的信息流方式,現(xiàn)在要獲取某個(gè)公眾號(hào)下面「所有文章列表」大概需要經(jīng)過以下四個(gè)步驟: 如果你的微信版本還不是信息流方式展示的,那么應(yīng)該是Android版本(微信采用的ABTest,不同的用戶呈現(xiàn)的方式不一樣) 同時(shí)觀察 Fiddler 主面板 進(jìn)入「全部消息」頁面時(shí),在 Fiddler 上已經(jīng)能看到有請(qǐng)求進(jìn)來了,說明公眾號(hào)的文章走的都是HTTP協(xié)議,這些請(qǐng)求就是微信客戶端向微信服務(wù)器發(fā)送的HTTP請(qǐng)求,。 注意:第一次請(qǐng)求「全部消息」的時(shí)候你看到的可能是一片空白: 在Fiddler或Charles中看到的請(qǐng)求數(shù)據(jù)是這樣的: 這個(gè)時(shí)候你要直接從左上角叉掉重新進(jìn)入「全部消息」頁面。 現(xiàn)在簡單介紹一下這個(gè)請(qǐng)求面板上的每個(gè)模塊的意義,。 這樣說明這個(gè)請(qǐng)求被微信服務(wù)器判定為一次非法的請(qǐng)求,這時(shí)你可以叉掉該頁面重新進(jìn)入「全部消息」頁面,。不出意外的話就能正常看到全部文章列表了,同時(shí)也能在Fiddler中看到正常的數(shù)據(jù)請(qǐng)求了,。 我把上面的主面板劃分為 7 大塊,你需要理解每塊的內(nèi)容,后面才有可能會(huì)用 Python 代碼來模擬微信請(qǐng)求,。 1、服務(wù)器的響應(yīng)結(jié)果,200 表示服務(wù)器對(duì)該請(qǐng)求響應(yīng)成功 TextView 模式下的預(yù)覽效果是服務(wù)器返回的 HTML 源代碼 WebView 模式是 HTML 代碼經(jīng)過渲染之后的效果,其實(shí)就是我們在手機(jī)微信中看到的效果,只不過因?yàn)槿狈邮?#xff0c;所以沒有手機(jī)上看到的美化效果,。 如果服務(wù)器返回的是 Json格式或者是 XML,你還可以切換到對(duì)應(yīng)的頁面預(yù)覽查看,。 小結(jié)配置好Fiddler的幾個(gè)步驟主要包括指定監(jiān)控的端口,開通HTTPS流量解密功能,同時(shí),客戶端需要安裝CA證書。下一節(jié)我們基于Requests模擬像微信服務(wù)器發(fā)起請(qǐng)求,。 抓取第一篇微信公眾號(hào)文章打開微信歷史消息頁面,我們從 Fiddler 看到了很多請(qǐng)求,為了找到微信歷史文章的接口,我們要逐個(gè)查看 Response 返回的內(nèi)容,最后發(fā)現(xiàn)第 11 個(gè)請(qǐng)求 "https://mp.weixin.qq.com/mp/profile_ext?action=home..." 就是我們要尋找的(我是怎么找到的呢?這個(gè)和你的經(jīng)驗(yàn)有關(guān),你可以點(diǎn)擊逐個(gè)請(qǐng)求,看看返回的Response內(nèi)容是不是期望的內(nèi)容) 確定微信公眾號(hào)的請(qǐng)求HOST是 mp.weixin.qq.com 之后,我們可以使用過濾器來過濾掉不相關(guān)的請(qǐng)求,。 爬蟲的基本原理就是模擬瀏覽器發(fā)送 HTTP 請(qǐng)求,然后從服務(wù)器得到響應(yīng)結(jié)果,現(xiàn)在我們就用 Python 實(shí)現(xiàn)如何發(fā)送一個(gè) HTTP 請(qǐng)求。這里我們使用 requests 庫來發(fā)送請(qǐng)求,。 創(chuàng)建一個(gè) Pycharm 項(xiàng)目 我們使用 Pycharm 作為開發(fā)工具,你也可以使用其它你熟悉的工具,Python 環(huán)境是 Python3(推薦使用 Python3.6),先創(chuàng)建一個(gè)項(xiàng)目 weixincrawler 現(xiàn)在我們來編寫一個(gè)最粗糙的版本,你需要做兩件事:
我們直接從 Fiddler 請(qǐng)求中拷貝 URL 和 Headers, 右鍵 -> Copy -> Just Url/Headers Only 最終拷貝出來的URL很長,它包含了很多的參數(shù):
暫且不去分析(猜測)每個(gè)參數(shù)的意義,也不知道那些參數(shù)是必須的,總之我把這些參數(shù)全部提取出來,。然后把 Headers 拷貝出來,發(fā)現(xiàn) Fiddler 把 請(qǐng)求行,、響應(yīng)行、響應(yīng)頭都包括進(jìn)來了,我們只需要中間的請(qǐng)求頭部分,。 因?yàn)?requests.get 方法里面的 headers 參數(shù)必須是字典對(duì)象,所以,先要寫個(gè)函數(shù)把剛剛拷貝的字符串轉(zhuǎn)換成字典對(duì)象,。
最終 v0.1 版本出來了,不出意外的話,公眾號(hào)歷史文章數(shù)據(jù)就在 response.text 中。如果返回的內(nèi)容非常短,而且title標(biāo)簽是
最后,我們順帶把響應(yīng)結(jié)果另存為html文件,以便后面重復(fù)使用,分析里面的內(nèi)容
用瀏覽器打開 weixin_history.html 文件,查看該頁面的源代碼,搜索微信歷史文章標(biāo)題的關(guān)鍵字 "11月贈(zèng)書"(就是我以往發(fā)的文章),你會(huì)發(fā)現(xiàn),歷史文章封裝在叫 msgList 的數(shù)組中(實(shí)際上該數(shù)組包裝在字典結(jié)構(gòu)中),這是一個(gè) Json 格式的數(shù)據(jù),但是里面還有 html 轉(zhuǎn)義字符需要處理 接下來我們就來寫一個(gè)方法提取出歷史文章數(shù)據(jù),分三個(gè)步驟,首先用正則提取數(shù)據(jù)內(nèi)容,然后 html 轉(zhuǎn)義處理,最終得到一個(gè)列表對(duì)象,返回最近發(fā)布的10篇文章,。
最終提取出來的數(shù)據(jù)總共有10條,就是最近發(fā)表的10條數(shù)據(jù),我們看看每條數(shù)據(jù)返回有哪些字段。
后面幾篇文章以列表的形式保存在 到此,公眾號(hào)文章的基本信息就抓到了,但也僅僅只是公眾號(hào)的前10條推送,。 資源來源于網(wǎng)絡(luò),純屬分享,不做商業(yè)用途,如若侵犯了您的權(quán)益和利益,請(qǐng)告知?jiǎng)h除。 |
|