如何利用Python網絡爬蟲抓取微信朋友圈的動態

朋友圈年度關鍵詞

1.引言

最近初學Python,寫爬蟲上癮。爬了豆瓣練手,又爬了公司的論壇生成詞雲分析年度關鍵詞。最近琢磨着2017又僅剩兩月了,我的年度關鍵詞是啥?
所以自然想到爬取下自己的微信朋友圈,來個詞頻分析,生成屬於自己的年度關鍵詞詞雲。

朋友圈的爬取是非常有難度的,因爲微信根本沒有暴露API入口去爬取數據。
但它山之石,可以攻玉。
通過各種搜索發現,已經有第三方工具可以做到朋友圈的導出。其中微信公衆號【出書啦】就提供了這樣一種服務,支持朋友圈導出,並排版生成微信書。

而對朋友圈的爬取就是基於【出書啦】爬取朋友圈後生成網頁後的二次爬取。
有點爬蟲經驗的,只要拿到導出朋友圈的URL,後面的爬蟲就不足爲道了。但本着分享和總結的精神,還是和大家娓娓道來。

=文中涉及個人隱私內容做了特殊處理=

2.獲取朋友圈數據入口

上面已經介紹過了朋友圈的數據爬取是基於【出書啦】微信公衆號生成的在線微信書數據的二次爬取。

具體步驟很簡單:

  1. 關注【出書啦】微信公衆號
  2. 點擊【創作書籍】-->【微信書】-->【開始製作】-->【添加隨機分配的出書啦小編爲好友即可】
  3. 稍等片刻,微信書製作完畢,會收到小編髮送的消息提醒,如下圖所示。

小編髮送的製作結果

點擊上圖的鏈接,我們就可以看到按照月份重新排版的朋友圈數據,如下圖所示:
重新排版後的微信朋友圈數據

至此,我們拿到朋友圈的數據入口——【出書啦】排版生成的微信書鏈接。

寫過爬蟲的,後面就可以直接略過了。
當然,沒寫過爬蟲也不想動手的,也可以把【出書啦】生成的微信書鏈接留言或私信給我,我幫你獲取年度關鍵詞。

3.環境準備

本文所寫爬蟲基於python2.7 + scrapy + jieba + wordcloud,使用VS Code IDE。

  1. Scrapy爲Python中比較流行的爬蟲框架。
  2. Jieba是比較好用的中文分詞模塊。
  3. Wordcloud 用於生成詞雲。

4.生成爬蟲項目

第一步:命令行執行scrapy startproject weixin_moment,生成Scrapy爬蟲項目。
第二步:進入創建的weixin_moment目錄,執行scrapy genspider 'moment' 'chushu.la'創建朋友圈爬蟲。
執行以上兩步後的文件夾結構如下:

爬蟲項目結構

5.分析數據源

數據的準確抓取,需要對數據源進行準確分析。這一步我們就要來分析【出書啦】生成的微信書鏈接的數據加載方式。老規矩,F12開發者工具用起來。

Http請求之目錄

從上圖我們可以看出這是一個get請求,返回的json類型格式數據。

點擊Preview頁籤可以看到如下圖所示的數據:

返回的目錄結果

從圖中可以看到返回的目錄導航數據包,其數據是按月份進行加載的。當點擊導航按鈕,其加載對應月份的朋友圈數據。

導航

我們點擊【2014-3】再觀察網絡請求,發現如下請求:

導航分頁請求

從以上數據我們可以明細看出,其採用的是用json傳參的post的方式請求數據包。點擊Preview頁籤,看到返回的分頁JSON數據包。

分頁請求返回的數據包

展開某個節點,我們可以發現朋友圈數據藏在data/paras節點下。

朋友圈數據

至此,我們完成數據的來源分析。

6.蜘蛛來也

完成了數據源分析,我們只需構造數據請求,並進行正確的數據解析,即可拿到我們想要的數據!

6.1.請求導航數據包

修改moment.py定義start_requests方法:

bookid = '12345678'  #請填寫【出書啦】返回鏈接中的數字部分
def start_requests(self):
        """
        使用get方式請求導航數據包
        """
        url = 'http://chushu.la/api/book/chushula-{0}?isAjax=1'.format(self.bookid)  #獲取目錄的url
        yield scrapy.Request(url, callback=self.parse)

重載parse方法,解析獲取到的導航數據包:

def parse(self, response):
        """
        處理獲取到的導航數據包
        """
        json_body = json.loads(response.body)  #加載json數據包
        catalogs = json_body['book']['catalogs']  #獲取json中的目錄數據包

6.2. 發送導航請求,抓取朋友圈數據

根據上面跟蹤到發出的http導航請求,要想抓取到朋友圈數據,我們需要根據發出的請求參數構造參數。

從上圖可知,主要包含五個參數:

  1. type:"year_month"爲默認值
  2. year: 年份
  3. month: 月份
  4. index: 第幾頁
  5. value : 由年月拼接的字符串

繼續修改我們的parse方法,遍歷我們第一步抓取到的導航數據包構造請求參數:

def parse(self, response):
        """
        處理獲取到的導航數據包
        """
        json_body = json.loads(response.body)  #加載json數據包
        catalogs = json_body['book']['catalogs']  #獲取json中的目錄數據包
        url = 'http://chushu.la/api/book/wx/chushula-{0}/pages?isAjax=1'.format(self.bookid) #分頁數據url
        start_page = int(catalogs[0]['month'])  #獲取起始月份作爲index傳值
        for catalog in catalogs:
            year = catalog['year']
            month = catalog['month']
            formdata = {
                "type": 'year_month',
                "year": year,
                "month": month,
                "index": str(start_page),
                "value": 'v_{0}{1}'.format(year, month)
            }
            start_page += 1

因爲從我們跟蹤到的http請求來看是基於json傳參的post請求:
所以我們要這樣發起請求:

yield scrapy.Request(
                url,
                method='POST',
                body=json.dumps(formdata),
                headers={'Content-Type': 'application/json'},
                callback=self.parse_moment)

同樣我們需要定義一個回調函數用來處理返回的朋友圈數據。定義parse_moment方法,根據返回的json數據包進行數據提取:

def parse_moment(self, response):
        """
        朋友圈數據處理
        """
        json_body = json.loads(response.body)
        pages = json_body['pages']
        pattern = re.compile(u"[\u4e00-\u9fa5]+")  #匹配中文
        item = WeixinMomentItem()
        for page in pages:
            if (page['type'] == "weixin_moment_page"):# 僅抓取朋友圈分頁數據
                paras = page['data']['paras']
                if paras:
                    moment = ''
                    for content in paras[0]['rows']:
                        result = re.findall(pattern,
                                            content['data'])  #使用正則匹配所有中文朋友圈
                        moment += ''.join(result)
                    item['moment'] = moment
                    item['date'] = page['data']['dateText']#獲取時間
                    yield item

以上用到了定義的WeixinMomentItem。修改items.py,做如下修改:

class WeixinMomentItem(scrapy.Item):
    """
    朋友圈Item
    """
    # define the fields for your item here like:
    # name = scrapy.Field()
    date = scrapy.Field()  #日期
    moment = scrapy.Field()  #朋友圈文字

至此我們完成爬蟲的書寫。是不是迫不及待跑一下。

6.3. 蜘蛛爬起來

命令行執行scrapy crawl moment -o moment.json,稍等片刻,熱乎的朋友圈數據就生成到moment.json文件中了。

爬取到的朋友圈文本

7. 分詞處理

jieba中文分詞提供了便利的接口用於分詞和詞頻統計。我們直接調用jieba.cut方法即可得到分詞結果。在此之前我們需要加載我們爬取的朋友圈數據,即保存到moment.json文件中的數據,並拼接所有朋友圈文本傳參至jieba.cut即可。
新添加一個analyse.py文件,定義analyse_words方法:

# -*- coding: utf-8 -*-

"""分析導出的朋友圈數據"""

import json
import os

import jieba
from wordcloud import WordCloud


def analyse_words():
    """
    分析抓取到的朋友圈數據,使用jieba進行分詞,使用wordcloud生成詞雲
    """
    curr_path = os.path.dirname(__file__)  # 當前文件文件夾所在目錄
    parent_path = os.path.dirname(curr_path)  # 上層目錄
    file_path = os.path.join(parent_path, 'moment.json')
    font_path = os.path.join(parent_path, "simhei.ttf")
    if not os.path.isfile(file_path):
        return
    with open(file_path) as moment_file:
        data = json.load(moment_file)  # 使用json加載文件
        moments = [item.get('moment', '') for item in data]  # 獲取朋友圈文字數組
        contents = ' '.join(moments)  # 拼接爲長文本
        cut_texts = ' '.join(jieba.cut(contents))  # 使用結巴分詞進行中文分詞

8. 生成關鍵詞詞雲

詞雲需要基於上一步的分詞結果生成詞雲。代碼也很簡單:

cloud = WordCloud(font_path=font_path)
        wordcloud = cloud.generate(cut_texts)  #生成詞雲
        wordcloud.to_file('keys.png')  #保存圖片
        image = wordcloud.to_image()  # 轉化爲圖片
        image.show()  # 展示圖片

最後在文件末尾調用analyse_words(),命令行執行python analyse.py即可生成關鍵詞!

生成的詞雲

你可能嫌棄以上生成的詞雲比較醜,沒關係,你可以使用wordart做出各種酷炫的效果。

9. 最後

因爲【出書啦】未完善反爬機制,所以爬蟲寫下來也沒有什麼難度,所以感興趣的不妨趕緊動手試一試。本文出於學習分享,無惡意竊取數據之意,也請讀者不要用於他途!

Python學習交流羣:548377875

作者:『聖傑』

出處:http://www.cnblogs.com/sheng-jie/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章