爬蟲實戰(三):微博用戶信息分析

前敘

系列文章:html

爬蟲實戰(一):爬取微博用戶信息python

爬蟲實戰(二):Selenium 模擬登陸並爬取信息git

爬蟲實戰(三):微博用戶信息分析github

該系列文章介紹了什麼?算法

1.爬蟲分析和處理方法數據庫

2.Python中的數據庫操做方法數組

3.Selenium瀏覽器自動化以及無頭瀏覽器使用方法瀏覽器

4.對數據進行詞雲分析的方法bash

5.對數據進行可視化的方法app

6.LDA隱含狄利克雷分佈模型的建模和使用方法

前言

前面 這篇文章 介紹了爬取微博用戶資料和動態並將數據保存在數據庫的過程。下面來講一下對數據庫數據與分析的過程。

數據庫分析

首先先來回顧一下前一篇文章中談到的數據庫字段。下圖是 weibo 數據庫中的三張表:

oXauR.png

其中每一個字段對應的含義請見源碼

再來看一下數據庫中每張表裏面的內容,首先是用戶資料表中的內容:

oXLLy.png

能夠看到和微博資料頁的資料是對應的。

再來看看用戶動態數據表:

oXEGi.png

裏面包含了用戶動態內容和動態發佈時間,因此咱們首先想到能夠對微博動態內容進行處理。

可視化分析

瞭解了數據庫結構之後,咱們能夠對微博動態和動態發佈時間進行可視化處理,在這裏,筆者作了如下幾點分析:

  • 微博動態發佈時間處理:畫出微博發佈時間統計圖
  • 微博動態簡單可視化:詞雲
  • 微博動態詞頻處理:詞頻統計以及生成詞頻圖

以上三種分析程序均位於 Data_analysis.py 中, 其 main 函數代碼以下:

#能夠指定須要分析的用戶的uid(必須先存在conf.yaml裏面,而且運行了一次爬蟲程序)
def main(uid):
    time_lists,str=get_time_str(uid)#將數據庫中的微博動態轉化爲字符串
    plot_create_time(time_lists)#畫出微博發佈時間統計圖
    with open('data/stop_words.txt') as f:
        stop_words = f.read().split('\n')
    str=format_content(str)#去掉表情和一些沒必要要的符號
    word_list=word_segmentation(str,stop_words)#分詞並去除停用詞
    create_wordcloud(word_list) #畫出詞雲
    counter = word_frequency(word_list, 10)# 返回前 top_N 個值,若是不指定則返回全部值
    print(counter)
    plot_chart(counter)#會生成詞頻圖保存在weibo_wordfrq.html中
複製代碼

那麼這三種分析具體如何實現呢?接下來筆者將對其進行一一闡述。

微博發佈時間統計

要對微博動態內容進行可視化分析,第一步是要將微博動態內容整合到一塊兒,下面這段代碼是將用戶微博中的全部動態拼接到一塊兒,也就是 main 函數裏面的第一行代碼所調用的函數。

# time_lists,str=get_time_str(uid)# main 函數第一行代碼
# 將數據庫中的微博動態轉化爲字符串
def get_time_str(uid):
    _, engine = Connect('../conf.yaml')  # 鏈接數據庫
    conn = engine.connect()
    metadata = MetaData(engine)
    wb_data = Table('wb_data',metadata, autoload=True)
    s = select([wb_data]).where(wb_data.c.uid == uid) #從wb_data表中選擇uid對應的數據
    res = conn.execute(s)
    conn.close()
    str = ''
    time_lists = []
    for row in res:
        str += row[2] + '\n'#拼接動態字段
        time_lists.append(row[3]) #將時間轉化爲列表對象,方便後續處理
    return time_lists, str
複製代碼

返回的 time_lists 爲動態發佈時間列表, str 爲全部動態拼接到一塊兒的最終字符串.在這裏由於是對時間進行統計,因此咱們只須要關注 time_lists 這個列表.先來看看這個列表裏面存放的具體內容:

[....,'02月02日 29', '01月21日 30', '01月20日 31', '01月10日 32', '01月02日 33', '01月01日 34', '2017-11-30', '2017-11-29', '2017-11-04', '2017-10-29', '2017-10-27',...]
複製代碼

這是我特地取的一段,恰好兩種格式的時間都包含在內。這個列表裏面包含的時間是從最近的月份和日期到最初的年份-月份-日期.例如上面的 '2017-11-30' 前面的日期格式均是 XX月XX日XX ,而 '01月01日 34' 後面的同理均是 20XX-XX-XX ,排序方式是由近到遠 。在這裏,我考慮分析天天發佈的微博動態數和時間的變化趨勢,而且將時間排列爲離如今越遠離原點越近。

因而便有了下面這段代碼:

# plot_create_time(time_lists)# main 函數第二行代碼
#畫出微博發佈時間的統計圖
def plot_create_time(time_lists):
    recent_time = re.compile(r'\d{2}月\d{2}日',re.S)
    long_time = re.compile(r'(\d{4}-\d{2}-\d{2})',re.S)
    tmp_lists = []#保存**月**日格式的數據
    tmp_nums = []#統計**月**日發帖數量
    long_lists = []#保存20**-**-**格式的數據
    long_nums = []#統計20**-**-**發帖數量
    for t in time_lists:
        res = re.findall(recent_time, t)
        if(res):#res[0]爲**月**日格式的數據
            if(not tmp_lists or res[0]!= tmp_lists[-1]):#列表爲空或者不與前一個日期重複
                tmp_lists.append(res[0])
                tmp_nums.append(1)
            else:#與前一個日期重複,計數加一
                tmp_nums[-1]+=1
        else:#res[0]20**-**-**格式的數據
            res = re.findall(long_time,t)

            if(not long_lists or res[0]!=long_lists[-1]):
                long_lists.append(res[0])
                long_nums.append(1)
            else:
                long_nums[-1]+=1
    #將時間按照從遠到進的順序排列
    tmp_lists.reverse()
    tmp_nums.reverse()
    long_lists.reverse()
    long_nums.reverse()
    time_list = long_lists + tmp_lists
    time_nums = long_nums + tmp_nums
    
    #調用 pyecharts 包渲染出統計圖
    chart = Bar('用戶微博動態發佈時間')
    chart.add('動態數', time_list, time_nums, is_more_utils=True,datazoom_range=[10,40],is_datazoom_show=True)
    chart.render("weibo_dynamic.html")
複製代碼

因而微博發佈時間統計圖便畫出來了,是一個動態的圖,效果以下:

weibo_dynamic.gif

詞雲分析

要對動態內容進行分析,首先要進行分詞處理,而且,咱們知道經常使用詞語中有不少語氣詞等,會影響關鍵詞語的權重,因此在進行分析以前須要去掉這些詞語,這種詞語在信息檢索叫作 停用詞 。此外,動態中含有的換行符,html代碼等沒必要要的符號也須要去掉。

因此 main 函數中在獲得詞雲以前有下面四行代碼:

with open('data/stop_words.txt') as f:#從保存有停用詞的文件中讀取停用詞
        stop_words = f.read().split('\n')
str=format_content(str)# 去掉表情和一些沒必要要的符號
word_list=word_segmentation(str,stop_words)#分詞並去除停用詞
複製代碼

其中調用了 word_segmentation 函數,該函數的內容以下:

# 分詞並去除停用詞
def word_segmentation(content, stop_words):
    # 使用 jieba 分詞對文本進行分詞處理
    jieba.enable_parallel()
    seg_list = jieba.cut(content)
    seg_list = list(seg_list)

    # 去除停用詞
    user_dict = [' ', '噠']
    filter_space = lambda w: w not in stop_words and w not in user_dict
    word_list = list(filter(filter_space, seg_list))

    return word_list
複製代碼

在這裏,我使用 jieba 進行分詞,再對分詞結果進行過濾,去除停用詞,並返回該分詞結果列表。而後使用 word_list 中的數據來畫出詞雲,具體代碼以下:

#create_wordcloud(word_list) # main 函數第7行代碼
#畫出詞雲
def create_wordcloud(content,image='weibo.jpg',max_words=5000,max_font_size=50):

    cut_text = " ".join(content)
    cloud = WordCloud(
        # 設置字體,不指定就會出現亂碼
        font_path="HYQiHei-25J.ttf",
        # 容許最大詞彙
        max_words=max_words,
        # 設置背景色
        # background_color='white',
        # 最大號字體
        max_font_size=max_font_size
    )
    word_cloud = cloud.generate(cut_text)
    word_cloud.to_file(image)
複製代碼

最後獲得結果 weibo.jpg ,打開看一看:

weibo.jpg

這就是詞雲分析的結果,讀者能夠根據本身須要,好比若是以爲原文和轉發出現頻率高價值不高能夠加入停用詞中進行過濾。

詞頻處理

對微博動態中的詞語出現的頻率進行統計處理,首先須要詞語列表,由於在詞雲分析中咱們已經獲得了過濾掉停用詞的詞語列表 word_list ,因此在這裏能夠直接拿來使用:

#counter = word_frequency(word_list, 10)# main 函數倒數第三行代碼
# 詞頻統計
# 返回前 top_N 個值,若是不指定則返回全部值
# from collections import Counter
def word_frequency(word_list, *top_N):
    if top_N:
        counter = Counter(word_list).most_common(top_N[0])
    else:
        counter = Counter(word_list).most_common()

    return counter
複製代碼

獲得的 counter 內容爲詞語以及出現的次數組成的列表,例如:

[('感受', 11), ('代碼', 10), ('說', 9),('晚上', 9), ('終於', 7), ('麻蛋', 6), ('寫', 6), ('數據', 5), ('學校', 5), ('朋友', 4)]
複製代碼

而後根據獲得的詞頻畫圖並渲染:

# plot_chart(counter)# main 函數最後一行,會生成詞頻圖保存在weibo_wordfrq.html中
#畫出詞頻圖,默認爲柱狀圖
def plot_chart(counter, chart_type='Bar'):
    items = [item[0] for item in counter]
    values = [item[1] for item in counter]

    if chart_type == 'Bar':
        chart = Bar('微博動態詞頻統計')
        chart.add('詞頻', items, values, is_more_utils=True)
    else:
        chart = Pie('微博動態詞頻統計')
        chart.add('詞頻', items, values, is_label_show=True, is_more_utils=True)

    chart.render('weibo_wordfrq.html')
複製代碼

最後獲得排名前10位的詞語頻率統計圖:

weibowordfrq.gif

LDA 分析

咱們忙活了好久,對用戶動態進行了多種分析,可是用戶的偏好和個性感受仍是沒有把握得很清楚,那麼這時候就須要使用一種方法從海量信息中抽取關鍵部分,最好是能提取出主題,受以前這篇論文[1] 的啓發,筆者得知 LDA 即是一種可以知足上述條件的很好的分析方法。

隱含狄利克雷分佈(英語:Latent Dirichlet allocation,簡稱LDA)是一種主題模型,它能夠將文檔集中每篇文檔的主題按照機率分佈的形式給出。同時它是一種無監督學習算法,在訓練時不須要手工標註的訓練集,須要的僅僅是文檔集以及指定主題的數量k便可。此外LDA的另外一個優勢則是,對於每個主題都可找出一些詞語來描述它。

以上說明摘錄自維基百科.

本文着眼點在於實踐,因此只介紹在 python 中使用 LDA 進行分析的方法,並不闡述 LDA 的原理。更況且,在計算機科學和數據科學的學術講座中,講者在介紹到LDA時,都每每會把原理這部分直接跳過去。

該部分代碼位於 LDA_Analysis.py ,首先能夠看看 main 函數的內容:

def main(uid):
    wordlists, uid = getwords(uid)#獲取分詞列表
    lda, tf, tf_feature_names, tf_vectorizer = word2vec(wordlists)#將單詞轉化爲向量
    Save_Topic_Words(lda, tf_feature_names, uid)#保存主題到數據庫
    pyLDAvisUI(lda, tf, tf_vectorizer)#根據主題結果進行渲染
複製代碼

第一步即是像以前那樣進行分詞並過濾停用詞,調用了 getwords 函數,代碼以下:

#獲取微博動態數據
def getwords(uid):
    _,str = get_time_str(uid)  # 將數據庫中的微博動態轉化爲字符串,能夠指定uid(conf.yaml裏面的)
    with open('data/stop_words.txt') as f:
        stop_words = f.read().split('\n')
    str = format_content(str)
    word_list = word_segmentation(str, stop_words)  # 分詞並去除停用詞
    return word_list,uid
複製代碼

該函數內容和以前介紹的 Data_analysis.py 中的效果同樣,故在此不累述。

而後使用 sklearn 機器學習包中自帶的 LDA 處理方法進行處理,代碼以下:

#lda, tf, tf_feature_names, tf_vectorizer = word2vec(wordlists)# main 函數第二行代碼
#使用LDA進行微博動態主題建模與分析
def word2vec(word_list,n_features=1000,topics = 5):
    tf_vectorizer = CountVectorizer(strip_accents='unicode',
                                    max_features=n_features,
                                    #stop_words='english',已經進行過停用詞處理故不用重複處理
                                    max_df=0.5,
                                    min_df=10)
    tf = tf_vectorizer.fit_transform(word_list)

    lda = LatentDirichletAllocation(n_components=topics,#主題數
                                    learning_method='batch',
                                   #樣本量不大隻是用來學習的話用"batch"比較好,這樣能夠少不少參數要調
                                    )
    #用變分貝葉斯方法訓練模型
    lda.fit(tf)

    #依次輸出每一個主題的關鍵詞表
    tf_feature_names = tf_vectorizer.get_feature_names()

    return lda,tf,tf_feature_names,tf_vectorizer #返回模型以及主題的關鍵詞表
複製代碼

最後咱們將主題以可視化結果展示出來:

#pyLDAvisUI(lda, tf, tf_vectorizer) # main 函數中最後一行
#將主題以可視化結果展示出來
def pyLDAvisUI(lda,tf,tf_vectorizer):

    page = pyLDAvis.sklearn.prepare(lda, tf, tf_vectorizer)
    pyLDAvis.save_html(page, 'lda.html')        #將主題可視化數據保存爲html文件
複製代碼

獲得 lda.html ,爲渲染之後的結果:

topic.gif

至此,用戶信息分析介紹結束。

源碼地址:github.com/starFalll/S…

參考:[1]陸飛.面向社會工程學的SNS分析和挖掘[D].上海:上海交通大學,2013.

相關文章
相關標籤/搜索