利用微信搜索抓取公衆號文章(轉載)

來源:http://www.shareditor.com/blogshow/44javascript


自動收集我關注的微信公衆號文章


 

2016.7.14 更新css

搜狐微信增長對referer驗證html

 

var page = require('webpage').create();

page.customHeaders={
    "referer":"http://weixin.sogou.com/weixin?oq=&query=關鍵詞"
}

 


 

 

個人微信裏關注了數十個有關大數據的公衆號,天天都會出現那個小紅點讓我點進去看,可是點多了就會以爲煩了,因此我要作的第一步就是自動把公衆號裏的新文章都收集到一塊,怎麼作呢?scrapy!java

對!scrapy抓取!可是scrapy順着超連接抓取web網頁容易,抓取微信app裏的內容就有難度了,暫時仍是作不到模擬一個收集app軟件。慶幸的是,騰訊和搜狗搜索結婚啦!生出了一個小寶寶:搜狗微信搜索。下面咱們就藉助搜狗微信搜索來實現個人目的python

舉個例子,我關注了一個公衆號叫:大數據文摘。打開http://weixin.sogou.com/,輸入「大數據文摘」,點「搜公衆號」,搜索結果以下:linux

點擊這個搜索結果,跳到了新頁面web

這裏面顯示的都是最新發布的文章算法

好!咱們就沿着這條路線來追蹤公衆號的新文章chrome

下面咱們來分析一下urlshell

第一個搜索結果頁的url是:http://weixin.sogou.com/weixin?type=1&query=%E5%A4%A7%E6%95%B0%E6%8D%AE%E6%96%87%E6%91%98&ie=utf8&_sug_=n&_sug_type_=,咱們去掉query之外的參數獲得:http://weixin.sogou.com/weixin?query=%E5%A4%A7%E6%95%B0%E6%8D%AE%E6%96%87%E6%91%98,打開以後結果是同樣的,ok,這個就做爲咱們抓取的種子入口,若是搜索其餘公衆號就把query參數換掉

下面分析搜索結果裏怎麼提取第二章頁面,也就是公衆號profile頁的連接,咱們看下搜索結果頁的部分html以下:

<div target="_blank" href="http://mp.weixin.qq.com/profile?src=3&amp;timestamp=1463443372&amp;ver=1&amp;signature=lNY-ZbjfPHr40G-zyUe*Sdc9HIn2IisEo0vwpKEAV*Z*ALBYuYf2HaMUtEP*15rQzs47zSEiORN3BOWPNA2R*A==" class="wx-rb bg-blue wx-rb_v1 _item" uigs_exp_id="" onclick="gotourl('http://mp.weixin.qq.com/profile?src=3&amp;timestamp=1463443372&amp;ver=1&amp;signature=lNY-ZbjfPHr40G-zyUe*Sdc9HIn2IisEo0vwpKEAV*Z*ALBYuYf2HaMUtEP*15rQzs47zSEiORN3BOWPNA2R*A==',event,this);return true;" id="sogou_vr_11002301_box_0" uigs="sogou_vr_11002301_box_0"> <div class="img-box"> <span class="ico-bg"></span><span class="ico-r"></span><img style="visibility: visible; height: 57px; margin-left: 0px;" src="http://img01.sogoucdn.com/app/a/100520090/oIWsFt58NVJTkYWvPtICKgg8ka60" onload="vrImgLoad(this, 'fit', 57, 57)" onerror="vrImgErr(this, '/wechat/images/account/def56-56.png')" extra="err:'http://img01.sogoucdn.com/net/a/04/link?appid=100520078&amp;url=http://wx.qlogo.cn/mmhead/Q3auHgzwzM46WJlQ8GYRWPhThl25rSKJEYBm408fnEkYS9DUkiaSxGg/0/0'"></div> <div class="txt-box"> <h3><em><!--red_beg-->大數據文摘<!--red_end--></em></h3> <h4> <span>微信號:<label name="em_weixinhao">BigDataDigest</label></span> </h4> <p class="s-p3"> <span class="sp-tit">功能介紹:</span><span class="sp-txt">普及<em><!--red_beg-->數據<!--red_end--></em>思惟,傳播<em><!--red_beg-->數據<!--red_end--></em>文化</span> </p> <p class="s-p3"> <span class="sp-tit"><script>authnamewrite('2')</script>微信認證:</span><span class="sp-txt">深圳大數據文摘科技有限公司</span> </p> <p class="s-p3"> <span class="sp-tit">最近文章:</span><span class="sp-txt"><a class="blue" target="_blank" id="sogou_vr_11002301_link_first_0" href="http://mp.weixin.qq.com/s?src=3&amp;timestamp=1463443372&amp;ver=1&amp;signature=fZ5HsUYiytbTgb8SekmcI3g9oizZncGBgdipWihPFh2pPnAwAwO62nX9iXNILZx0XtQB3R*3PWcgqPh1YWL*LX3qxIOf0ZpkKyhZSUkAgPmH*w71dqIB2*wfNTpVDZx5G3nh31tctf*lNqXlfXzgfPO6E60vqoqB694bPMymy*I=" title="二項式與小蘋果——看牛頓如何將靈感火花拓展成知識體系">二項式與小蘋果——看牛頓如何將靈感火花拓展成知識體系</a><span class="hui"><script>vrTimeHandle552write('1463440604')</script>46分鐘前</span></span> </p> ……

看這裏關鍵的href一行:

<div target="_blank" href="http://mp.weixin.qq.com/profile?src=3&amp;timestamp=1463443372&amp;ver=1&amp;signature=lNY-ZbjfPHr40G-zyUe*Sdc9HIn2IisEo0vwpKEAV*Z*ALBYuYf2HaMUtEP*15rQzs47zSEiORN3BOWPNA2R*A==" class="wx-rb bg-blue wx-rb_v1 _item" uigs_exp_id="" onclick="gotourl('http://mp.weixin.qq.com/profile?src=3&amp;timestamp=1463443372&amp;ver=1&amp;signature=lNY-ZbjfPHr40G-zyUe*Sdc9HIn2IisEo0vwpKEAV*Z*ALBYuYf2HaMUtEP*15rQzs47zSEiORN3BOWPNA2R*A==',event,this);return true;" id="sogou_vr_11002301_box_0" uigs="sogou_vr_11002301_box_0">

這就是咱們要提取的profile頁連接,提取方式能夠直接通配成:「url裏帶http://mp.weixin.qq.com/profile?src=的href屬性」

 

ps:找xpath的方便方法是利用瀏覽器的開發者工具,好比chrome界面以下:

在Elements的標籤處點右鍵選擇:Copy->Copy XPath,就自動把xpath路徑拷貝到剪切板了

 

注意:在這裏我忽然想到一個問題,每一個公衆號對應的profile頁面是否是永遠不變的呢?通過個人實驗,這條url裏的timestamp參數和signature是有對應關係的,任意一個錯了都沒法打開,並且每次搜索生成的連接都是不一樣的,因此我判定在微信搜索內容是動態生成連接的,那麼這個動態連接的生命週期就不可預測了,因此爲了保險起見,咱們每次都從搜索入口追溯,纔是萬全之策

下面咱們分析profile頁裏的文章連接,咱們看profile頁的部分 html以下:

<h4 class="weui_media_title" hrefs="/s?timestamp=1463443165&amp;src=3&amp;ver=1&amp;signature=dZCo9et5C6nyZfVAQAl416OW-eXJbi0VaS0QPQdvEv1tawqgsjlVYUd0oav0tUHAf38HOGU3Lskd7qqXbFg9D2mP8cv36CZ1dW0bGxbP4YyJcRdy*M*Mow6xD5YWDK8-82r9MX*4WqgbGqo4FAhZeiGTEl27YhIbaIxPiQgMbxc=">代理銀行業務:經過監管列表對代理銀行客戶進行風險評級</h4> <p class="weui_media_desc">爲了確保銀行積極的經過代理銀行關係來鏈接美國金融市場,須要考慮如何根據現有電匯和監管列表信息,來提高可疑行爲模型的成熟度。</p> <p class="weui_media_extra_info">2016年5月17日</p>

這裏面能夠找到文章的內容了連接、標題、摘要、發佈時間,簡直太完美了

連接的提取方式能夠直接通配成:h4.weui_media_title hrefs

標題的提取方式能夠直接通配成:h4.weui_media_title text

摘要的提取方式能夠直接通配成:p.weui_media_desc

發佈時間的提取方式能夠直接通配成:p.weui_media_extra_info

 

開發個人scrapy爬蟲

 

若是尚未安裝scrapy,請見《教你成爲全棧工程師(Full Stack Developer) 三十-十分鐘掌握最強大的python爬蟲

建立一個scrapy工程

scrapy startproject weixin

在weixin/spiders/中建立dashujuwenzhai.py內容以下:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import scrapy

class ShareditorSpider(scrapy.Spider):
    name = "dashujuwenzhai"
    allowed_domains = ["qq.com"]
    start_urls = [
        "http://weixin.sogou.com/weixin?query=大數據文摘"
    ]

    def parse(self, response):
        print response.body
        href = response.selector.xpath('//div[@id="sogou_vr_11002301_box_0"]/@href').extract()[0]
        yield scrapy.Request(href, callback=self.parse_profile)

    def parse_profile(self, response):
        print response.body

執行

scrapy crawl dashujuwenzhai

便可以抓到大數據文摘的profile頁面內容

請尊重原創,轉載請註明來源網站www.shareditor.com以及原始連接地址

接下來來研究profile頁,抓回的頁面不是普通的html頁面,而是經過js渲染出來的,也就是咱們看到的每一條文章的標題、摘要等都是經過js計算出來的,代碼裏有這麼一句:

var msgList = '{&quot;list&quot;:[{&quot;comm_msg_info&quot;:{&quot;id&quot;:410106318,&quot;type&quot;:49,&quot;datetime&quot;:1463528503,&quot;fakeid&quot;:&quot;2391437564&quot;,&quot;status&quot;:2,&quot;content&quot;:&quot;&quot;},&quot;app_msg_ext_info&quot;:{&quot;title&quot;:&quot;機器人前傳:達芬奇的機器獅和日耳曼裝甲騎士&quot;,&quot;digest&quot;:&quot;這是一篇描述阿爾法狗和Atlas機器人祖先的文章。遠在500多年前的達芬奇時代,已經有了很多關於機器人的探索。這個大天才寫了大量關於自動機描述,在他的我的筆記中也充斥着各類機械發明的構思,好比彈簧驅動的汽車和機器獅子。&quot;,&quot;content&quot;:&quot;&quot;,&quot;fileid&quot;:504157567,&quot;content_url&quot;:&quot;\\/s?timestamp=1463529354&amp;amp;src=3&amp;amp;ver=1&amp;amp;signature=cG*R8qc-PGKV-aZ4q9IlJQfIHtGp5I3H63xlK-h5mBO0W2FRAzCddav9cPf*GuwUBI4x0zJzmtcoOU7sQQeMf3CfNzaTEIq4C8YwnsZQGnqnauqr2wQYvEFvAooyecPF3H6bg8OiqpSZsd5LnY*fVrZOMINmQwV8Qup*D9qvUkw=&quot;,&quot;source_url&quot;:&quot;https:\\/\\/mp.weixin.qq.com\\/s?__biz=MzA4OTYwNzk0NA==&amp;amp;mid=401744027&amp;amp;idx=1&amp;amp;sn=43699667dca4438a49db51fb3700af4f&amp;amp;scene=1&amp;amp;srcid=0517MRoAk1EzgC5iSMtvoYC5&amp;amp;pass_ticket=06ybKvJknob%2F5%2B%2FAmkUtnjcyCqWcuNxZTJapLW5QZyk7PWh1jD7ubwb5H1zXzMWB#rd&quot;,&quot;cover&quot;:&quot;http:\\/\\/mmbiz.qpic.cn\\/mmbiz\\/wc7YNPm3YxXiajPXq2Y2PWQsic1SmjCxnTicHKtwItmARwkha1RI1gH1WwTfRvEUzauWJibjuJC9oJ8eibeVlDjRkwg\\/0?wx_fmt=jpeg&quot;,&quot;subtype&quot;:0,&quot;is_multi&quot;:1,&quot;multi_app_msg_item_list&quot;:[{&quot;title&quot;:&quot;清華論壇實錄|劉瑞寶:洞見數據內涵,提高公共安全研判能力&quot;,&quot;digest&quot;:&quot;本文爲劉瑞寶先生於2016年3月24日在RONG—大數據與公共安全專場上所作的題爲《洞見數據內涵,提高公共安全研判能力》的演講實錄。&quot;,&quot;content&quot;:&quot;&quot;,&quot;fileid&quot;:504157565,&quot;content_url&quot;:&quot;\\/s?timestamp=1463529354&amp;amp;src=3&amp;amp;ver=1&amp;amp;signature=cG*R8qc-PGKV-aZ4q9IlJQfIHtGp5I3H63xlK-h5mBO0W2FRAzCddav9cPf*GuwUBI4x0zJzmtcoOU7sQQeMf3CfNzaTEIq4C8YwnsZQGnrmdiX-aBZzJtqDGa76CoHH8gL7PEfN3ZQN5lNa4YgJUeUyE*SIna3B7W*zKWYskkU=&quot;,&quot;source_url&quot;:&quot;https:\\/\\/mp.weixin.qq.com\\/s?__biz=MzAxMzA2MDYxMw==&amp;amp;mid=2651555964&amp;amp;idx=2&amp;amp;sn=479aaf7f3b687b973ffa303d3d3be6b9&amp;amp;scene=1&amp;amp;srcid=0517C5DgLArlrdVAlQ9GIHOl&amp;amp;pass_ticket=06ybKvJknob%2F5%2B ……

固然尚未截取全,這就是文章的所有內容,寫到了一個js變量裏,這樣就沒法經過scrapy原生的response.xpath拿到,這怎麼辦呢?

咱們來利用phantomjs來渲染,這是一個強大的工具,它是無界面的瀏覽器,因此渲染js速度很是快,可是也有一些缺陷,有一些瀏覽器渲染功能不支持,因此若是再深刻能夠藉助selenium工具,這又是一個強大的工具,它本來是用來作web應用程序自動化測試用的,也就是能夠模擬各類點擊瀏覽等動做,那麼用他來作爬蟲幾乎就是一個真人,本節先來研究phantomjs,有關selenium的內容後面有需求了再研究

 

安裝phantomjs

wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
tar jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
cd phantomjs-2.1.1-linux-x86_64/
./bin/phantomjs examples/netlog.js http://www.shareditor.com/

以上輸出了網路通訊日誌,說明沒有問題

 

爲了方便,能夠把./bin/phantomjs拷貝到~/bin下

 

寫一個phantomjs渲染腳本

var page = require('webpage').create();
var system = require('system');
page.open(system.args[1], function(status) {
    var sc = page.evaluate(function() {
        return document.body.innerHTML;
    });
    window.setTimeout(function() {
        console.log(sc);
        phantom.exit();
    }, 100);
});

建立phantomjs渲染腳本getBody.js內容以下:

 

執行

phantomjs getBody.js 'http://mp.weixin.qq.com/profile?src=3&timestamp=1463529344&ver=1&signature=lNY-ZbjfPHr40G-zyUe*Sdc9HIn2IisEo0vwpKEAV*Z*ALBYuYf2HaMUtEP*15rQ7TpyhXFL52e8W929D4nd2g==' > profile.html

這裏的連接可能已經失效,請換成在搜狗微信搜索搜到某個公衆號profile頁面裏的某一篇文章的url

打開profile.html會發現內容已經被渲染完成了,每篇文章的地方變成了:

<div id="WXAPPMSG410106318" class="weui_media_box appmsg" msgid="410106318">
                        <span class="weui_media_hd" style="background-image:url(http://mmbiz.qpic.cn/mmbiz/wc7YNPm3YxXiajPXq2Y2PWQsic1SmjCxnTicHKtwItmARwkha1RI1gH1WwTfRvEUzauWJibjuJC9oJ8eibeVlDjRkwg/0?wx_fmt=jpeg)" data-s="640" data-t="1463528503000" hrefs="/s?timestamp
                        <div class="weui_media_bd">
                            <h4 class="weui_media_title" hrefs="/s?timestamp=1463531541&amp;src=3&amp;ver=1&amp;signature=n187YKNZjqgxyUtJ*yFEQGG7wJOH79RQeRrjQ0RGRdKEiZmR6iM0oNE5P0DPbQEwWTnShlZ4C3JIZr9PYThxbnhuCPl2UTc5NGE0ZkARKXEhTqCe7QvAGFf8vy2QWnPKqA9iSBBgBrocHKLBAuTM

                            機器人前傳:達芬奇的機器獅和日耳曼裝甲騎士
                            </h4>
                            <p class="weui_media_desc">這是一篇描述阿爾法狗和Atlas機器人祖先的文章。遠在500多年前的達芬奇時代,已經有了很多關於機器人的探索。這個大天才寫了大量關於自動機描述,在他的我的筆記中也充斥着各類機械發明的構思,好比彈簧驅動的汽車和機器獅子。</p>
                            <p class="weui_media_extra_info">2016年5月18日</p>
                        </div>
                    </div> ​

這即可以經過scrapy的request.xpath提取了

 

從新完善咱們的scrapy爬蟲腳本

 

#!/usr/bin/python
# -*- coding: utf-8 -*-
import scrapy
import subprocess
from scrapy.http import HtmlResponse
from scrapy.selector import Selector

class ShareditorSpider(scrapy.Spider):
    name = "dashujuwenzhai"
    allowed_domains = ["qq.com"]
    start_urls = [
        "http://weixin.sogou.com/weixin?query=算法與數學之美"
    ]

    def parse(self, response):
        href = response.selector.xpath('//div[@id="sogou_vr_11002301_box_0"]/@href').extract()[0]
        cmd="~/bin/phantomjs ./getBody.js '%s'" % href
        stdout, stderr = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()
        response = HtmlResponse(url=href, body=stdout)

        for selector in Selector(response=response).xpath('//*[@id="history"]/div/div/div/div'):
            hrefs= selector.xpath('h4/@hrefs').extract()[0].strip()
            title = selector.xpath('h4/text()').extract()[0].strip()
            abstract = selector.xpath('//*[contains(@class, "weui_media_desc")]/text()').extract()[0].strip()
            pubtime = selector.xpath('//*[contains(@class, "weui_media_extra_info")]/text()').extract()[0].strip()
            print hrefs
            print title
            print abstract
            print pubtime

    def parse_profile(self, response):
        print response.body

這是一段我用了數天精力創形成功的一段代碼,耗費了我不少體力值,因此重點講解一下

href = response.selector.xpath('//div[@id="sogou_vr_11002301_box_0"]/@href').extract()[0]

從公衆號搜索結果頁裏提取profile頁面的連接,這個id我懷疑不久後將失效,因此若是想作完美,還得不斷完善,有關xpath的使用技巧能夠參考http://ejohn.org/blog/xpath-css-selectors/

cmd="~/bin/phantomjs ./getBody.js '%s'" % href
stdout, stderr = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()

加載phantomjs腳本getBody.js來渲染profile頁面,把裏面的js渲染成html

response = HtmlResponse(url=href, body=stdout)

用渲染後的html頁面來建立一個HtmlResponse,用於 後面繼續xpath提信息

Selector(response=response).xpath('//*[@id="history"]/div/div/div/div')

找到每一條文章模塊所在的div

hrefs= selector.xpath('//h4/@hrefs').extract()[0].strip()
title = selector.xpath('h4/text()').extract()[0].strip()
abstract = selector.xpath('//*[contains(@class, "weui_media_desc")]/text()').extract()[0].strip()
pubtime = selector.xpath('//*[contains(@class, "weui_media_extra_info")]/text()').extract()[0].strip()

根據這個div結構提取各個字段

 

基於這個爬蟲腳本,想造就怎樣的神奇,就看你以後的想象力了,沒有作不到,只有想不到!

 


 

 

Python處理HTML轉義字符

html = '&lt;abc&gt;'

用Python能夠這樣處理:

import HTMLParser
html_parser = HTMLParser.HTMLParser()
txt = html_parser.unescape(html) #這樣就獲得了txt = '<abc>'

 

若是還想轉回去,能夠這樣:

 

import cgi
html = cgi.escape(txt) # 這樣又回到了 html = '&lt;abc&gt'

 

python對json的相關操做

使用簡單的json.dumps方法對簡單數據類型進行編碼,例如:

import json
 
obj = [[1,2,3],123,123.123,'abc',{'key1':(1,2,3),'key2':(4,5,6)}]
encodedjson = json.dumps(obj)
print repr(obj)
print encodedjson

輸出:

[[1, 2, 3], 123, 123.123, 'abc', {'key2': (4, 5, 6), 'key1': (1, 2, 3)}] 

[[1, 2, 3], 123, 123.123, "abc", {"key2": [4, 5, 6], "key1": [1, 2, 3]}]

 

從json到python的類型轉化對照以下:

decodejson = json.loads(encodedjson)
print type(decodejson)
print decodejson[4]['key1']
print decodejson

輸出:

<type 'list'> 
[1, 2, 3]

[[1, 2, 3], 123, 123.123, u'abc', {u'key2': [4, 5, 6], u'key1': [1, 2, 3]}]

 

參考:

 

http://www.cnblogs.com/coser/archive/2011/12/14/2287739.html

相關文章
相關標籤/搜索