您的位置:首页 > 大数据

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

2020-04-19 19:50 656 查看

该系列文章是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/12323815

文章目录

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

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


    一.人民网数据抓取

    本文抓取数据为人民网某专栏的新闻数据。数据包括重要新闻、人民评论、实况武汉、各地动态、八方支援等专栏,通过抓取新闻数据进行主题关键词分析和知识图谱构建。下面以YQ快速为例,先进行网页分析,再抓取相关的新闻数据。
    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(('序号','文章标题','发布时间','文章链接','文章内容'))
    
    #--------------------------------------------YQ快讯-数据抓取---------------------------------------------
    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共现,在他们之间建立一条边。共现矩阵如下所示:

    [−ABCDA0121B1011C2101D1110](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} ⎣⎢⎢⎢⎢⎡​−ABCD​A0121​B1011​C2101​D1110​⎦⎥⎥⎥⎥⎤​(1)

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

    [SourceTargetWeightAB1AC2AD1BC1BD1CD1](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} ⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡​SourceAAABBC​TargetBCDCDD​Weight121111​⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤​(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彼此链接在了一起。将一个粉圈的头目和一个黑圈头目,看似一点也不相关的账户给联系在了一起。是不是就达到了通过一个用户查找到群体的目的呀~

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

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

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

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


    六.总结

    写到这里,第五篇YQ分析的文章就讲解完毕,希望对您有所帮助,尤其是想写文本挖掘论文的读者。后续还会分享舆情分析、威胁情报溯源、预测预警及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简易学习[六]———— 拓展分析红楼梦数据

    • 点赞 8
    • 收藏
    • 分享
    • 文章举报
    Eastmount 博客专家 发布了454 篇原创文章 · 获赞 6502 · 访问量 508万+ 他的留言板 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: