人生苦短,我用Python && C#。
1.引言
最近初學Python,寫爬蟲上癮。爬了豆瓣練手,又爬了公司的論壇生成詞雲分析年度關鍵詞。最近琢磨着2017又僅剩兩月了,我的年度關鍵詞是啥?
所以自然想到爬取下自己的微信朋友圈,來個詞頻分析,生成屬於自己的年度關鍵詞詞雲。
朋友圈的爬取是非常有難度的,因為微信根本沒有暴露API入口去爬取數據。
但它山之石,可以攻玉。
通過各種搜索發現,已經有第三方工具可以做到朋友圈的導出。其中微信公眾號【出書啦】就提供了這樣一種服務,支持朋友圈導出,並排版生成微信書。
而對朋友圈的爬取就是基於【出書啦】爬取朋友圈后生成網頁后的二次爬取。
有點爬蟲經驗的,只要拿到導出朋友圈的URL,后面的爬蟲就不足為道了。但本着分享和總結的精神,還是和大家娓娓道來。
=文中涉及個人隱私內容做了特殊處理=
2.獲取朋友圈數據入口
上面已經介紹過了朋友圈的數據爬取是基於【出書啦】微信公眾號生成的在線微信書數據的二次爬取。
具體步驟很簡單:
- 關注【出書啦】微信公眾號
- 點擊【創作書籍】-->【微信書】-->【開始制作】-->【添加隨機分配的出書啦小編為好友即可】
- 稍等片刻,微信書制作完畢,會收到小編發送的消息提醒,如下圖所示。
點擊上圖的鏈接,我們就可以看到按照月份重新排版的朋友圈數據,如下圖所示:
至此,我們拿到朋友圈的數據入口——【出書啦】排版生成的微信書鏈接。
寫過爬蟲的,后面就可以直接略過了。
當然,沒寫過爬蟲也不想動手的,也可以把【出書啦】生成的微信書鏈接留言或私信給我,我幫你獲取年度關鍵詞。
3.環境准備
本文所寫爬蟲基於python2.7 + scrapy + jieba + wordcloud,使用VS Code IDE。
4.生成爬蟲項目
第一步:命令行執行scrapy startproject weixin_moment
,生成Scrapy爬蟲項目。
第二步:進入創建的weixin_moment目錄,執行scrapy genspider 'moment' 'chushu.la'
創建朋友圈爬蟲。
執行以上兩步后的文件夾結構如下:
5.分析數據源
數據的准確抓取,需要對數據源進行准確分析。這一步我們就要來分析【出書啦】生成的微信書鏈接的數據加載方式。老規矩,F12開發者工具用起來。
從上圖我們可以看出這是一個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導航請求,要想抓取到朋友圈數據,我們需要根據發出的請求參數構造參數。
從上圖可知,主要包含五個參數:
- type:"year_month"為默認值
- year: 年份
- month: 月份
- index: 第幾頁
- 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. 最后
因為【出書啦】未完善反爬機制,所以爬蟲寫下來也沒有什么難度,所以感興趣的不妨趕緊動手試一試。本文出於學習分享,無惡意竊取數據之意,也請讀者不要用於他途!