接上篇檐蚜,這一篇將從技術(shù)層面講講是如何實現(xiàn)的府阀。閱讀本文您將會了解如何用python爬取微博的評論以及如何用python word_cloud庫進行數(shù)據(jù)可視化失乾。
上一篇:程序員代碼下的許豪杰
準(zhǔn)備工作
打開微博pc m站并找到許豪杰該條微博地址:https://m.weibo.cn/status/4132385564040383
為什么要用m站地址?因為m站可以直接抓取到api json數(shù)據(jù),而pc站雖然也有api返回的是html,相比而言選取m站會省去很多麻煩
打開該頁面,并且用chrome 的檢查工具 查看network横腿,可以獲取到評論的api地址。
數(shù)據(jù)抓取
首先觀察api返回
從返回地址上可以看到可以通過參數(shù)page 改變請求的頁碼,并且每頁都回返回總條數(shù)和總頁碼數(shù)斤寂。這里我決定采用多線程來抓去(其實數(shù)據(jù)量不大,也可以單線程跑)耿焊。
其中在爬取數(shù)據(jù)的時候會面臨幾個問題:
1.存儲選擇
我這里選用了MongoDB作為數(shù)據(jù)存儲,因為api通常返回的是json數(shù)據(jù)而json結(jié)構(gòu)和MongoDB的存儲方式可以結(jié)合的很默契遍搞,不需要經(jīng)過任何處理可以直接的進行插入罗侯。
2.防爬蟲
很多網(wǎng)站可能會做一些防爬蟲的處理,面對同一個請求ip的短時間的高頻率請求會進行服務(wù)隔斷(直接告訴你服務(wù)不可用)溪猿,這個時候可以去網(wǎng)上找一些代理進行請求钩杰。
3.多線程的任務(wù)分配
采用多線程爬取你當(dāng)然不能讓多個線程去爬取同樣的鏈接做別人已經(jīng)做過的事情,那樣多線程毫無意義诊县。所以你需要制定一套規(guī)則讲弄,讓不同線程爬取不同的鏈接。
# coding=utf-8
from __future__ import division
from pymongo import MongoClient
import requests
import sys
import re
import random
import time
import logging
import threading
import json
from os import path
import math
# 爬取微博評論
# m站微博地址
weibo_url = 'https://m.weibo.cn/status/4132385564040383'
thread_nums = 5 #線程數(shù)
#代理地址
proxies = {
"http": "http://171.92.4.67:9000",
"http": "http://163.125.222.240:8118",
"http": "http://121.232.145.251:9000",
"http": "http://121.232.147.247:9000",
}
# 創(chuàng)建 日志 對象
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
mongoconn = MongoClient('127.0.0.1', 27017)
mdb = mongoconn.data_analysis
das_collection = mdb.weibo
weiboid_reobj = re.match(r'.*status/(\d+)', weibo_url)
weibo_id = weiboid_reobj.group(1)
def scrapy_comments(weibo_id, page):
weibo_comment_url = 'https://m.weibo.cn/api/comments/show?id=%s&page=%d' % (
weibo_id, page)
res = requests.get(weibo_comment_url)
res_obj = json.loads(res.content)
return res_obj
def import_comments(threadName, weibo_id, page_start, page_end):
logger.info('開始線程:%s' % threadName)
for page in range(page_start, page_end + 1):
logging.info('讀取第%s頁' % page)
time.sleep(1)
# continue
try:
res_obj = scrapy_comments(weibo_id, page)
logging.info('該頁有%s條記錄' % len(res_obj['data']))
except:
logging.error('讀取%s頁時發(fā)生錯誤' % page)
continue
if res_obj['ok'] == 1:
comments = res_obj['data']
for comment in comments:
comment_text = re.sub(
r'</?\w+[^>]*>', '', comment['text']).encode('utf-8')
if re.search(r'回復(fù)@.*:', comment_text):
# 過濾掉回復(fù)別人的評論
continue
comment['text'] = comment_text
comment['weibo_id'] = weibo_id
logging.info('讀取評論:%s' % comment['id'])
try:
if das_collection.find_one({'id': comment['id']}):
logging.info('在mongodb中存在')
else:
logging.info('插入記錄:%s' % comment['id'])
das_collection.insert_one(comment)
except:
logging.error('mongodb發(fā)生錯誤')
else:
logging.error('讀取第%s頁時發(fā)生錯誤' % page)
logging.info('線程%s結(jié)束' % threadName)
# res_obj = scrapy_comments(weibo_id, page)
if __name__ == '__main__':
# 分配不同鏈接到不同的線程上去
res_obj = scrapy_comments(weibo_id, 1)
if res_obj['ok'] == 1:
total_number = res_obj['total_number']
logging.info('該條微博有:%s條評論' % total_number)
max_page = res_obj['max']
page_nums = math.ceil(max_page / thread_nums)
else:
raise
# print max_page
# print page_nums
for i in range(1, thread_nums + 1):
if i < thread_nums:
page_end = page_nums * i
else:
page_end = max_page
page_start = (i - 1) * page_nums + 1
t = threading.Thread(target=import_comments, args=(
i, weibo_id, int(page_start), int(page_end)))
t.start()
數(shù)據(jù)整理可視化(data visualization)
運行腳本完畢依痊,我的MongoDB得到了2萬多條評論數(shù)據(jù)避除,接下來要做的事是對這部分?jǐn)?shù)據(jù)進行提取、清洗胸嘁、結(jié)構(gòu)化等操作瓶摆。這里順便說明一下python 數(shù)據(jù)分析的 大致基本流程。
1.與外界進行交互
這個過程包括數(shù)據(jù)的獲取性宏、讀取群井。不管是從網(wǎng)絡(luò)資源上爬取、還是從現(xiàn)有資源(各樣的文件如文本毫胜、excel书斜、數(shù)據(jù)庫存儲對象)
2.準(zhǔn)備工作
對數(shù)據(jù)進行清洗(cleaning)、修整(munging)指蚁、整合(combining)菩佑、規(guī)范化(normalizing)、重塑(reshaping)凝化、切片(slicing)和切塊(dicing)
3.轉(zhuǎn)換
對數(shù)據(jù)集做一些數(shù)學(xué)和統(tǒng)計運算產(chǎn)生新的數(shù)據(jù)集
4.建模和計算
將數(shù)據(jù)跟統(tǒng)計模型稍坯、機器學(xué)習(xí)算法或其他計算工具聯(lián)系起來
5.展示
創(chuàng)建交互式的或靜態(tài)的圖片或文字摘要
下面我們來進行2、3及5的工作:
# coding=utf-8
import sys
from pymongo import MongoClient
import random
# 分詞庫
# from snownlp import SnowNLP
import jieba
import uniout
from collections import Counter, OrderedDict
# 詞語云 文本統(tǒng)計可視化庫
from wordcloud import WordCloud
mongoconn = MongoClient('127.0.0.1', 27017)
mdb = mongoconn.data_analysis
das_collection = mdb.weibo
total_counts = das_collection.find().count()
# random_int = random.randint(0, total_counts - 1)
docs = das_collection.find()
print docs.count()
words_counts = {}
for doc in docs:
print doc
comment_text = doc['text'].encode('utf-8')
if len(comment_text) == 0:
continue
words = jieba.cut(comment_text)
for word in words:
if word not in words_counts:
words_counts[word] = 1
else:
words_counts[word] += 1
for word in words_counts.keys():
if words_counts[word] < 2 or len(word) < 2:
del words_counts[word]
# print words_counts.items()
#注意要讓中文不亂碼要指定中文字體
#fit_words 接收參數(shù)是dict eg:{'你':333,'好':23} 文字:出現(xiàn)次數(shù)
wordcloud = WordCloud(
font_path='/Users/cwp/font/msyh.ttf',
background_color='white',
width=1200,
height=1000
).fit_words(words_counts)
import matplotlib.pyplot as plt
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.show()
介紹下以上代碼:
我們主要用到了2個工具,jieba和word_cloud瞧哟。前者對中文進行分詞后者圖形化展示詞語的出現(xiàn)頻率混巧。
眾所周知,中文系的語言處理恐怕是最難的自然語言處理(NLP)的語種勤揩。就基本的分詞而言都是一項比較困難的工作,(英語句子中每個單詞都是有空格分開的咧党,而中文是由單個字組成詞連接成串組成句).
舉個例子,請用“孩提”造句,"那個男孩提交完代碼就下班了"。如果人工分詞陨亡,可以知道"男孩"和"提交"應(yīng)該是分開的2個詞傍衡,但是對于機器而言,要辨別"提"應(yīng)該與"男"還是"交"進行組詞就很難辦了负蠕。要想機器能夠更精確的辨別這類問題蛙埂,就需要讓機器不停學(xué)習(xí),讓它知道這種情況該這么分而不是那么分遮糖。研究中文自然語言處理將是一個長久而大的工程绣的,對于分析數(shù)據(jù)(我們不是要研究自然語言處理??),這里就借助jieba這個庫進行工作了.
對于word_cloud,圖形化文本統(tǒng)計欲账,網(wǎng)上有不少的博文都貼了代碼屡江,但我想說的是我不了解它們是不是真的運行出了結(jié)果。因為fit_words 這個函數(shù)接收的是dict而不是list赛不,官方文檔和函數(shù)doc其實寫錯了,在github上有披露惩嘉。
最后得到結(jié)果:
一些用到的工具
1.word_cloud A little word cloud generator in Python
3.Requests is the only Non-GMO HTTP library for Python, safe for human consumption.