[Pyhon疫情大数据分析] 五.人民网话题抓取及Gephi构建疫情主题知识图谱

该系列文章是Python大数据分析疫情系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警及AI和NLP应用等。希望该系列文章对您有所帮助,武汉加油、湖北加油、全国加油。待到疫情结束樱花盛开,这座英雄的城市等你们来。

前文分享了采用SnowNLP对微博话题进行简单的情感分析及文本挖掘。这篇文章将讲解Python抓取人民网新闻,并利用Gephi构建疫情主题知识图谱,发现各主题关键词的关联。希望这篇基础性文章对您有所帮助,也非常感谢参考文献中老师的分享!如果您有想学习的知识或建议,可以给作者留言~

本文的重点不是数据抓取,请读者结合自己的需求和数据进行分析,也可以直接使用作者的数据集,希望给大家知识图谱提供一点思路。就作者而言,知识图谱包括两种类型,一种是Google于2012年提出的Knowledge Graph(下一代搜索引擎),另一种是图书情报和文献分析的知识图谱,这里其实介于两者之间,也建议读者结合自己领域理解。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码下载地址:https://github.com/eastmountyxz/Wuhan-data-analysis
CSDN下载地址:https://download.csdn.net/download/Eastmount/12239638

同时推荐前面作者另外五个Python系列文章。从2014年开始,作者主要写了三个Python系列文章,分别是基础知识、网络爬虫和数据分析。2018年陆续增加了Python图像识别和Python人工智能专栏。

在这里插入图片描述

前文阅读:
[Pyhon疫情大数据分析] 一.腾讯实时数据爬取、Matplotlib和Seaborn可视化分析全国各地区、某省各城市、新增趋势
[Pyhon疫情大数据分析] 二.PyEcharts绘制全国各地区、某省各城市疫情地图及可视化分析
[Pyhon疫情大数据分析] 三.新闻信息抓取及词云可视化、文本聚类和LDA主题模型文本挖掘
[Pyhon疫情大数据分析] 四.微博话题抓取及新冠肺炎疫情文本挖掘和情感分析



一.人民网数据抓取

本文抓取数据为人民网“众志成城,抗击疫情”专栏的新闻数据。

在这里插入图片描述

数据包括重要新闻、人民评论、实况武汉、各地动态、八方支援等专栏,通过抓取新闻数据进行主题关键词分析和知识图谱构建。

在这里插入图片描述

下面以疫情快速为例,先进行网页分析,再抓取相关的新闻数据。
http://society.people.com.cn/GB/369130/431577/431608/index.html

在这里插入图片描述

本文采用Selenium和BeautifulSoup进行抓取,定位网页节点关键代码如下:

  • 标题:titles = driver.find_elements_by_xpath(’//div[@class=" p2j_list_lt fl"]/ul/li’)
  • 链接:links = driver.find_elements_by_xpath(’//div[@class=" p2j_list_lt fl"]/ul/li/a’)

在这里插入图片描述

获取标题、时间、链接之后,我们通过访问链接获取正文信息,核心代码如下:

  • zw = soup.find(attrs={“class”:“box_con”})

在这里插入图片描述

完整代码:

# -*- coding: utf-8 -*-
import os
import re
import csv
import time
import json
import random
import urllib.request
from lxml import etree
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options


#-------------------------------------------------写入文件-------------------------------------------------
path = os.getcwd() + "/yqkx_data.csv"
csvfile = open(path, 'a', newline='', encoding = 'utf-8-sig')
writer = csv.writer(csvfile)
writer.writerow(('序号','文章标题','发布时间','文章链接','文章内容')) 

#--------------------------------------------疫情快讯-数据抓取---------------------------------------------
url = "http://society.people.com.cn/GB/369130/431577/431608/index.html"
driver = webdriver.Chrome() #chromedriver.exe置于python37根目录
driver.implicitly_wait(5)
chrome_option = webdriver.ChromeOptions()
driver.get(url) #打开网页网页
driver.implicitly_wait(6) #等待加载六秒

#-------------------------------------------------获取标题-------------------------------------------------
titles = driver.find_elements_by_xpath('//div[@class=" p2j_list_lt fl"]/ul/li')
for t in titles:
    print(t.text)

links = driver.find_elements_by_xpath('//div[@class=" p2j_list_lt fl"]/ul/li/a')
for link in links:
    print(link.get_attribute('href'))

print("\n\n==========================================================")

#-------------------------------------------------获取正文-------------------------------------------------
def get_content(url):
    print(url)
    try:
        content = urllib.request.urlopen(url).read()
        soup = BeautifulSoup(content,"html.parser")
        #来源
        ly = soup.find(attrs={"class":"fl"}).get_text()
        #print(ly)
        #正文
        zw = soup.find(attrs={"class":"box_con"})
        #防止某些文章仅图片
        if zw is not None:
            zw = zw.get_text()
            zw = zw.replace("\n", "")
        else:
            zw = ""
        print(zw)
        print("succeed")
        return ly,zw
    except Exception as e:
        zw = e.partial
        ly = ""
        print("except")
        print(zw)
    return ly, page
    
#-------------------------------------------------写入文件-------------------------------------------------
k = 0
while k<len(titles):
    #序号
    num = str(k+1)
    #文章标题和发布时间
    value = titles[k].text.split('\n')
    con_title = value[0]
    con_time = value[1]
    #文件链接
    url = links[k].get_attribute('href')
    #获取来源和正文
    ly,zw = get_content(url)
    content = (num, con_title, con_time, url, zw)
    #文件写入操作
    writer.writerow((content))
    k = k + 1

#文件关闭
csvfile.close() 

数据抓取如下图所示:

在这里插入图片描述

存储至CSV文件如下图所示:

在这里插入图片描述



二.文本关键词提取

作者抓取了多个专栏,汇总相关数据如下图所示(可从github下载)。由于论文原因,作者仅公开每个专栏的50篇新闻,包括:八方支援、各地动态、抗疫英雄、权威解读、人民网评、实况武汉、一线守护、疫情快讯。

在这里插入图片描述

数据如下图所示:

在这里插入图片描述

作者提取新闻正文内容或新闻标题进行词频分析,存储为“all-data.txt”。

在这里插入图片描述

接下来的代码是中文分词,并提取每条新闻排名前50的关键词,作为后续的共现分析和知识图谱构建。

# coding=utf-8
import jieba
import re
import time
from collections import Counter
from snownlp import SnowNLP

#------------------------------------中文分词------------------------------------
cut_words = ""
all_words = ""
f = open('all-data-key.txt', 'w', encoding='utf-8')
for line in open('all-data.txt', encoding='utf-8'):
    line = line.strip('\n')
    #停用词过滤
    line = re.sub('[0-9’!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~\s]+', "", line)
    seg_list = jieba.cut(line, cut_all=False)
    cut_words = (" ".join(seg_list))

    #计算关键词
    all_words = cut_words.split()
    c = Counter()
    for x in all_words:
        if len(x)>1 and x != '\r\n':
            c[x] += 1
    #Top50
    output = ""
    #print('\n词频统计结果:')
    for (k,v) in c.most_common(50):
        #print("%s:%d"%(k,v))
        output += k + " "
    
    f.write(output+"\n")
else:
    f.close()

运行结构如下图所示,每一行表示一条新闻的Top50关键词,接下来需要计算它们的共现矩阵。

在这里插入图片描述

在这里插入图片描述



三.共现矩阵

引文分析常见的包括两类,一种是共现关系,另一种是引用和被引用关系。本文主要讲解共现关系,假设现在存在三篇文章,如下所示:

文章标题                                        作者
大数据发展现状分析                              A,B,C
Python网络爬虫                                 A,D,C
贵州省大数据战略                                 D,B

(1) 首先写代码抓取该领域文章的所有作者或关键词,即:A、B、C、D。
(2) 接着获取对应的共现矩阵,比如文章“大数据发展现状分析”,则认为A、B、C共现,在他们之间建立一条边。共现矩阵如下所示:

[ A B C D A 0 1 2 1 B 1 0 1 1 C 2 1 0 1 D 1 1 1 0 ] (1) \left[ \begin{matrix} -& A & B & C & D \\ A & 0 & 1 & 2 & 1 \\ B & 1 & 0 & 1 & 1 \\ C & 2 & 1 & 0 & 1 \\ D & 1 & 1 & 1 & 0 \end{matrix} \right] \tag{1}

(3) 通过共现矩阵分别获取两两关系及权重,再写入CSV或Excel文件中,如下所示。

[ S o u r c e T a r g e t W e i g h t A B 1 A C 2 A D 1 B C 1 B D 1 C D 1 ] (2) \left[ \begin{matrix} Source & Target & Weight \\ A & B & 1 \\ A & C & 2 \\ A & D & 1 \\ B & C & 1 \\ B & D & 1\\ C & D & 1 \end{matrix} \right] \tag{2}

(4) 将该CSV文件导入Gephi中,并绘制相关的图形。因为该实例节点比较少,下面是Pyhton调用Networkx绘制的代码及图形。

# -*- coding: utf-8 -*-
import networkx as nx
import matplotlib.pyplot as plt
 
#定义有向图
DG = nx.Graph() 
#添加五个节点(列表)
DG.add_nodes_from(['A', 'B', 'C', 'D'])
print(DG.nodes())
#添加边(列表)
DG.add_edge('A', 'B', weight=1)
DG.add_edge('A', 'C', weight=2)
DG.add_edge('A', 'D', weight=1)
DG.add_edge('B', 'C', weight=1)
DG.add_edge('B', 'D', weight=1)
DG.add_edge('C', 'D', weight=1)
#DG.add_edges_from([('A', 'B'), ('A', 'C'), ('A', 'D'), ('B','C'),('B','D'),('C','D')])
print(DG.edges())
#绘制图形 设置节点名显示\节点大小\节点颜色
colors = ['red', 'green', 'blue', 'yellow']
nx.draw(DG,with_labels=True, node_size=900, node_color = colors)
plt.show()

绘制图形如下所示:

大家也可以采用PyEcharts绘制网络图、Neo4j图数据库绘制关系图。由于我们的数据集比较多,故推荐大家使用Gephi软件绘制相关图形,而且图形比较美观。



四.主题关键词共现分析

下面的代码是获取每条新闻主题关键词的共现矩阵,代码如下:

# -*- coding: utf-8 -*-
"""
@author: eastmount CSDN 2020-04-12
"""
import pandas as pd
import numpy as np
import codecs
import networkx as nx
import matplotlib.pyplot as plt
import csv
from scipy.sparse import coo_matrix
 
#---------------------------第一步:读取数据-------------------------------
word = [] #记录关键词
f = open("all-data-key.txt", encoding='utf-8')            
line = f.readline()           
while line:
    #print line
    line = line.replace("\n", "") #过滤换行
    line = line.strip('\n') 
    for n in line.split(' '):
        #print n
        if n not in word:
            word.append(n)
    line = f.readline()
f.close()
print(len(word)) #关键词总数

#--------------------------第二步 计算共现矩阵----------------------------
a = np.zeros([2,3])
print(a)

#共现矩阵
#word_vector = np.zeros([len(word),len(word)], dtype='float16') 

#MemoryError:矩阵过大汇报内存错误
#采用coo_matrix函数解决该问题
print(len(word))
#类型<type 'numpy.ndarray'>
word_vector = coo_matrix((len(word),len(word)), dtype=np.int8).toarray() 
print(word_vector.shape)

f = open("all-data-key.txt", encoding='utf-8')  
line = f.readline()           
while line:
    line = line.replace("\n", "") #过滤换行
    line = line.strip('\n') #过滤换行
    nums = line.split(' ')

    #循环遍历关键词所在位置 设置word_vector计数
    i = 0
    j = 0
    while i<len(nums):         #ABCD共现 AB AC AD BC BD CD加1
        j = i + 1
        w1 = nums[i]           #第一个单词
        while j<len(nums):
            w2 = nums[j]       #第二个单词
            #从word数组中找到单词对应的下标
            k = 0
            n1 = 0
            while k<len(word):
                if w1==word[k]:
                    n1 = k
                    break
                k = k +1
            #寻找第二个关键字位置
            k = 0
            n2 = 0
            while k<len(word):
                if w2==word[k]:
                    n2 = k
                    break
                k = k +1
            #重点: 词频矩阵赋值 只计算上三角
            if n1<=n2:
                word_vector[n1][n2] = word_vector[n1][n2] + 1
            else:
                word_vector[n2][n1] = word_vector[n2][n1] + 1
            #print n1, n2, w1, w2
            j = j + 1
        i = i + 1
    #读取新内容
    line = f.readline()
f.close()

#--------------------------第三步  TXT文件写入--------------------------
res = open("word_word_weight.txt", "a+", encoding='utf-8')
i = 0
while i<len(word):
    w1 = word[i]
    j = 0
    while j<len(word):
        w2 = word[j]
        #判断两个词是否共现 共现&词频不为0的写入文件
        if word_vector[i][j]>0:
            #print w1 +" " + w2 + " "+ str(int(word_vector[i][j]))
            res.write(w1 +" " + w2 + " "+ str(int(word_vector[i][j]))  +  "\n")
        j = j + 1
    i = i + 1
res.close()

#--------------------------第四步  CSV文件写入--------------------------
c = open("word-word-weight.csv","w", encoding='utf-8', newline='')    #解决空行
#c.write(codecs.BOM_UTF8)                                 #防止乱码
writer = csv.writer(c)                                    #写入对象
writer.writerow(['Word1', 'Word2', 'Weight'])

i = 0
while i<len(word):
    w1 = word[i]
    j = 0 
    while j<len(word):
        w2 = word[j]
        #判断两个词是否共现 共现词频不为0的写入文件
        if word_vector[i][j]>0:
            #写入文件
            templist = []
            templist.append(w1)
            templist.append(w2)
            templist.append(str(int(word_vector[i][j])))
            #print templist
            writer.writerow(templist)
        j = j + 1
    i = i + 1
c.close()

输出结果如下所示:

5267
[[0. 0. 0.]
 [0. 0. 0.]]
5267
(5267, 5267)

生成如下图所示共现关系,主题词word1和word2共现weight词,共计33,0341条关系。

在这里插入图片描述

由于主题关系较多会影响绘制的知识图谱,而我们的分析目的是提取核心关键词的关联关系。因此接下来需要进行数据预处理,将关系权重(Weight)小于等于9的都过滤。最终得到“word-word-weight-gl9.csv”文件,共计3177条关系。

在这里插入图片描述



五.Gephi绘制主题知识图谱

1.数据准备

实体构建:324个主题关键词或实体
构建实体表“entity.csv”,包括id编号和label类标名称,共324个主题关键词(实体),如下图所示。这里采用的方法是将“word-word-weight-gl9.csv”文件的Word1和Word2关键词复制至一列并删除重复项,而真实的知识图谱需要通过命令实体识别来提取,如果想知道这部分内容,后续我也可以尝试分享。

在这里插入图片描述

关系构建:3177条关系
构建关系表“relationship.csv”,包括Source起始实体、Target目标实体、Type类型(无方向)和Weight权重,共3177条三元关系<实体,关系,实体>,如下图所示。

在这里插入图片描述



2.导入数据

第一步,新建工程,并选择“数据资料”,输入电子表格。

在这里插入图片描述

第二步,导入节点表格,选择entity实体表。

在这里插入图片描述

第三步,导入数据如下图所示,设置为“边表格”,注意CSV表格数据一定设置为 Source(起始点)、Target(目标点)、Weight(权重),这个必须和Gephi格式一致,否则导入数据会提示错误。

在这里插入图片描述

导入数据如下图所示,它们是无向图。

在这里插入图片描述

第四步,导入成功后点击“概览”显示如下所示,接着就是调整参数。

在这里插入图片描述



3.调整参数绘制图谱

设置外观如下图所示,主要包括颜色、大小、标签颜色、标签尺寸。

在这里插入图片描述

第一步,设置节点大小和颜色。
选中颜色,点击“数值设定”,选择渲染方式为“度”。

在这里插入图片描述

显示结果如下所示:

在这里插入图片描述

接着设置节点大小,数值设定为“度”,最小尺寸为20,最大尺寸为120。

在这里插入图片描述


第二步,设置模块化。
在右边统计中点击“运行”,设置模块性。

在这里插入图片描述

在这里插入图片描述


第三步,设置平均路径长度。
在右边统计中点击“运行”,设置边概述。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


第四步,重新设置节点属性。
节点大小数值设定为“度”,最小值还是20,最大值还是120。节点颜色数值设定为“Modularity Class”,表示模块化。

在这里插入图片描述


第五步,设置边大小和颜色。
设置边颜色的数值设定为“边的权重”,如下图所示。

在这里插入图片描述

在这里插入图片描述

设置边的大小数值设定为“边的权重”。

在这里插入图片描述


第六步,在布局中选择“Fruchterman Reingold”。
调整区、重力和速度。

在这里插入图片描述

显示结果如下所示:

在这里插入图片描述


第七步,点击预览。
设置宋体字,显示标签,透明度调整为20,如下图所示。

在这里插入图片描述

最终结构如下图所示。

在这里插入图片描述

导出PNG、PDF、SVG如下图所示。

在这里插入图片描述



4.图谱优化

第一步,图谱调整。

在这里插入图片描述

选择喜欢的颜色。

在这里插入图片描述

边的厚度调整。

在这里插入图片描述

最终显示结果如下图所示:

在这里插入图片描述


第二步,权重过滤。
我们可以使用滤波功能过滤一些不重要的点,让重要的点清晰可见。滤波可以对节点做过滤,也可以对边做过滤。节点过滤:在属性中,可以做到节点的过滤,可以通过节点的lable、weight做等于、范围值、非空等过滤。如下图,就是通过节点的weight进行了范围的过滤,过滤掉了低weight值的节点,让这个图形不重要的节点变少。

在这里插入图片描述

在右上有一个“上下文”,展示的节点量、边量,做完过滤之后,这块会展示过滤后的量和占比。

在这里插入图片描述

做完了过滤之后,仍然可以继续执行布局的自动运行,直到节点的排列符合你的目的。

在这里插入图片描述

从下图可以看到一个大的社群,由三个小社群组成(粉色圈、黑色圈和部分灰色圈),他们之间通过两个uid彼此链接在了一起。将一个粉圈的头目和一个黑圈头目,看似一点也不相关的账户给联系在了一起。是不是就达到了通过一个用户查找到群体的目的呀~

在这里插入图片描述

最后删除掉无关联的节点,可以移动到一起区域删除,最终得到如下图所示的知识图谱。不知道是否有更好的方法?

在这里插入图片描述

最终得到如下图所示的知识图谱。

在这里插入图片描述

在这里插入图片描述

我们也可以设置其他布局,如下图所示:

在这里插入图片描述

最终如下图所示,如果增加停用词过滤效果更好些。

在这里插入图片描述



六.总结

写到这里,第五篇疫情分析的文章就讲解完毕,希望对您有所帮助,尤其是想写文本挖掘论文的读者。后续还会分享舆情分析、威胁情报溯源、预测预警及AI和NLP应用等。如果文章对您有所帮助,将是我写作的最大动力。作者将源代码上传至github,大家可以直接下载。你们的支持就是我撰写的最大动力,加油~

同时,向钟院士致敬,向一线工作者致敬。侠之大者,为国为民。咱们中国人一生的最高追求,为天地立心,为生民立命,为往圣继绝学,为万世开太平。以一人之力系万民康乐,以一身犯险保大业安全。他们真是做到了,武汉加油,中国加油!

在这里插入图片描述

(By:Eastmount 2020-04-12 周末下午5点于贵阳 http://blog.csdn.net/eastmount/)



参考文献:
[1] [关系图谱] 一.Gephi通过共现矩阵构建知网作者关系图谱
[2] [关系图谱] 二.Gephi导入共线矩阵构建作者关系图谱
[3] [Python知识图谱] 一.哈工大pyltp安装及中文分句、中文分词、导入词典基本用法
[4] [Python知识图谱] 二.哈工大pyltp词性标注、命名实体识别、依存句法分析和语义角色标注
[5] [Python知识图谱] 三.Jieba工具中文分词、添加自定义词典及词性标注详解
[6] [Python知识图谱] 四.Python和Gephi实现中国知网合作关系知识图谱
[7] 知识图谱相关会议之观后感分享与学习总结
[8] 中文知识图谱研讨会的学习总结 (上) 图谱引入、百度知心、搜狗知立方
[9] 搜索引擎和知识图谱那些事 (上).基础篇
[10] Gephi的使用–以社交网络图为例 - Yan Li
[11] Gephi简易学习[六]———— 拓展分析红楼梦数据

发布了453 篇原创文章 · 获赞 6424 · 访问量 505万+

猜你喜欢

转载自blog.csdn.net/Eastmount/article/details/105462139