• Python 文本语义识别,文本转化为图数据库,文本摘要图展示,文本结构化为图谱


    一、文本语义识别,并进行图谱化表示:

    1.统计词频

    文本预处理:对文本进行分句、分词,统计词频

    2.textrank

    (1).TextRank算法是由PageRank算法改进而来的,二者的思想有相同之处,区别在于:PageRank算法根据网页之间的链接关系构造网络,而TextRank算法根据词之间的共现关系构造网络;PageRank算法构造的网络中的边是有向无权边,而TextRank算法构造的网络中的边是无向有权边。

    (2).TextRank 算法是一种用于文本的基于图的排序算法,通过把文本分割成若干组成单元(句子/词),构建节点连接图,用句子(词)之间的相似度作为边的权重,通过循环迭代计算句子(词)的TextRank值,最后抽取排名高的句子(词)组合成文本摘要。

    (3).如果一个单词出现在很多单词后面的话,那么说明这个单词比较重要

    一个TextRank值很高的单词后面跟着的单词,那么这个单词的TextRank值会相应地因此而提高。

    公式:

    TextRank中一个单词 i 的权重取决于与在 i 前面的各个单词j组成的( j , i ) 这条边的权重,以及j这个单词到其他边的权重之和。

    1. 第一步是把所有文章整合成文本数据
    2. 接下来把文本分割成单个句子
    3. 然后,我们将为每个句子找到向量表示(词向量)。
    4. 计算句子向量间的相似性并存放在矩阵中
    5. 然后将相似矩阵转换为以句子为节点、相似性得分为边的图结构,用于句子TextRank计算。
    6. 最后,一定数量的排名最高的句子构成最后的摘要。

    3.命名实体识别(NER)

    此处ner用的模块为pyltp。语言技术平台(LTP) 是由 哈工大社会计算与信息检索研究中心 11 
    年的持续研发而形成的一个自然语言处理工具库,其提供包括中文分词、词性标注、命名实体识别、依存句法分析、语义角色标注等丰富、高效、精准的自然语言处理技术。LTP制定了基于XML的语言处理结果表示,并在此基础上提供了一整套自底向上的丰富而且高效的中文语言处理模块(包括词法、句法、语义等6项中文处理核心技术),以及基于动态链接库(Dynamic 
    Link Library, DLL)的应用程序接口,可视化工具,并且能够以网络服务(Web Service)的形式进行使用。pyltp即python版的ltp。

    此处需要提前下载ltp训练好的模型数据。

    二.实现思路和代码:

    主要分为四个模块,分别是主模块,textrank模块,ner模块,图谱构建模块。

    1.主模块:即主要包含数据的预处理,即清洗数据、分句、统计词频等步骤,以及执行的主函数,负责调用其它模块和最终结果的生成。

    代码部分:

    1. from sentence_parser import *
    2. import re
    3. from collections import Counter
    4. from GraphShow import *
    5. from keywords_textrank import *
    6. '''事件挖掘'''
    7. class CrimeMining:
    8. def __init__(self):
    9. self.textranker = TextRank()
    10. self.parser = LtpParser()
    11. self.ners = ['nh', 'ni', 'ns']
    12. self.ner_dict = {
    13. 'nh':'人物',
    14. 'ni':'机构',
    15. 'ns':'地名'
    16. }
    17. self.graph_shower = GraphShow()
    18. '''移除括号内的信息,去除噪声'''
    19. def remove_noisy(self, content):
    20. p1 = re.compile(r'([^)]*)')
    21. p2 = re.compile(r'\([^\)]*\)')
    22. return p2.sub('', p1.sub('', content))
    23. '''收集命名实体'''
    24. def collect_ners(self, words, postags):
    25. ners = []
    26. for index, pos in enumerate(postags):
    27. if pos in self.ners:
    28. ners.append(words[index] + '/' + pos)
    29. # print(ners)
    30. return ners
    31. '''对文章进行分句处理'''
    32. def seg_content(self, content):
    33. return [sentence for sentence in re.split(r'[??!!。;;::\n\r]', content) if sentence]
    34. '''对句子进行分词,词性标注处理'''
    35. def process_sent(self, sent):
    36. words, postags = self.parser.basic_process(sent)
    37. # print('words:',words)
    38. # print('postags:',postags)
    39. return words, postags
    40. '''构建实体之间的共现关系'''
    41. def collect_coexist(self, ner_sents, ners):
    42. co_list = []
    43. for sent in ner_sents:
    44. words = [i[0] + '/' + i[1] for i in zip(sent[0], sent[1])]
    45. co_ners = set(ners).intersection(set(words))
    46. co_info = self.combination(list(co_ners))
    47. co_list += co_info
    48. if not co_list:
    49. return []
    50. return {i[0]:i[1] for i in Counter(co_list).most_common()}
    51. '''列表全排列'''
    52. def combination(self, a):
    53. combines = []
    54. if len(a) == 0:
    55. return []
    56. for i in a:
    57. for j in a:
    58. if i == j:
    59. continue
    60. combines.append('@'.join([i, j]))
    61. return combines
    62. '''抽取出事件三元组'''
    63. def extract_triples(self, words, postags):
    64. svo = []
    65. tuples, child_dict_list = self.parser.parser_main(words, postags)
    66. # print(tuples)
    67. for tuple in tuples:
    68. rel = tuple[-1]
    69. if rel in ['SBV']:
    70. sub_wd = tuple[1]
    71. verb_wd = tuple[3]
    72. obj = self.complete_VOB(verb_wd, child_dict_list)
    73. subj = sub_wd
    74. verb = verb_wd
    75. if not obj:
    76. svo.append([subj, verb])
    77. else:
    78. svo.append([subj, verb+obj])
    79. return svo
    80. '''过滤出与命名实体相关的事件三元组'''
    81. def filter_triples(self, triples, ners):
    82. ner_triples = []
    83. for ner in ners:
    84. for triple in triples:
    85. if ner in triple:
    86. ner_triples.append(triple)
    87. return ner_triples
    88. '''根据SBV找VOB'''
    89. def complete_VOB(self, verb, child_dict_list):
    90. for child in child_dict_list:
    91. wd = child[0]
    92. attr = child[3]
    93. if wd == verb:
    94. if 'VOB' not in attr:
    95. continue
    96. vob = attr['VOB'][0]
    97. obj = vob[1]
    98. return obj
    99. return ''
    100. '''对文章进行关键词挖掘'''
    101. def extract_keywords(self, words_list):
    102. return self.textranker.extract_keywords(words_list, 10)
    103. '''基于文章关键词,建立起实体与关键词之间的关系'''
    104. def rel_entity_keyword(self, ners, keyword, subsent):
    105. events = []
    106. rels = []
    107. sents = []
    108. ners = [i.split('/')[0] for i in set(ners)]
    109. keyword = [i[0] for i in keyword]
    110. for sent in subsent:
    111. tmp = []
    112. for wd in sent:
    113. if wd in ners + keyword:
    114. tmp.append(wd)
    115. if len(tmp) > 1:
    116. sents.append(tmp)
    117. for ner in ners:
    118. for sent in sents:
    119. if ner in sent:
    120. tmp = ['->'.join([ner, wd]) for wd in sent if wd in keyword and wd != ner and len(wd) > 1]
    121. if tmp:
    122. rels += tmp
    123. for e in set(rels):
    124. events.append([e.split('->')[0], e.split('->')[1]])
    125. return events
    126. '''利用标点符号,将文章进行短句切分处理'''
    127. def seg_short_content(self, content):
    128. return [sentence for sentence in re.split(r'[,,??!!。;;::\n\r\t ]', content) if sentence]
    129. '''挖掘主控函数'''
    130. def main(self, content):
    131. if not content:
    132. return []
    133. # 对文章进行去噪处理
    134. content = self.remove_noisy(content)
    135. # 对文章进行长句切分处理
    136. sents = self.seg_content(content)
    137. # 对文章进行短句切分处理
    138. subsents = self.seg_short_content(content)
    139. subsents_seg = []
    140. # words_list存储整篇文章的词频信息
    141. words_list = []
    142. # ner_sents保存具有命名实体的句子
    143. ner_sents = []
    144. # ners保存命名实体
    145. ners = []
    146. # triples保存主谓宾短语
    147. triples = []
    148. # 存储文章事件
    149. events = []
    150. for sent in subsents:
    151. words, postags = self.process_sent(sent)
    152. words_list += [[i[0], i[1]] for i in zip(words, postags)]
    153. subsents_seg.append([i[0] for i in zip(words, postags)])
    154. ner = self.collect_ners(words, postags)
    155. # print(sent,ners)
    156. if ner:
    157. triple = self.extract_triples(words, postags)
    158. if not triple:
    159. continue
    160. triples += triple
    161. ners += ner
    162. ner_sents.append([words, postags])
    163. # print(triples)
    164. # 获取文章关键词, 并图谱组织, 这个可以做
    165. keywords = [i[0] for i in self.extract_keywords(words_list)]
    166. for keyword in keywords:
    167. name = keyword
    168. cate = '关键词'
    169. events.append([name, cate])
    170. # 对三元组进行event构建,这个可以做
    171. for t in triples:
    172. if (t[0] in keywords or t[1] in keywords) and len(t[0]) > 1 and len(t[1]) > 1:
    173. events.append([t[0], t[1]])
    174. # 获取文章词频信息话,并图谱组织,这个可以做
    175. word_dict = [i for i in Counter([i[0] for i in words_list if i[1][0] in ['n', 'v'] and len(i[0]) > 1]).most_common()][:10]
    176. for wd in word_dict:
    177. name = wd[0]
    178. cate = '高频词'
    179. events.append([name, cate])
    180. # 获取全文命名实体,这个可以做
    181. ner_dict = {i[0]:i[1] for i in Counter(ners).most_common()}
    182. for ner in ner_dict:
    183. name = ner.split('/')[0]
    184. cate = self.ner_dict[ner.split('/')[1]]
    185. events.append([name, cate])
    186. # 获取全文命名实体共现信息,构建事件共现网络
    187. co_dict = self.collect_coexist(ner_sents, list(ner_dict.keys()))
    188. co_events = [[i.split('@')[0].split('/')[0], i.split('@')[1].split('/')[0]] for i in co_dict]
    189. events += co_events
    190. #将关键词与实体进行关系抽取
    191. events_entity_keyword = self.rel_entity_keyword(ners, keywords, subsents_seg)
    192. events += events_entity_keyword
    193. print(events)
    194. #对事件网络进行图谱化展示
    195. self.graph_shower.create_page(events)
    196. if __name__ == '__main__':
    197. content8 = '''
    198. 身为一名学习委员,同学的作业要立马交了就立马送到老师办公室。
    199. 因为我们是两个语文学习文员,但共同干同一件事——收全班同学的语文作业。
    200. 当时竞选班长,我被选上当语文学习委员,而另一个同学曾经已经是语文学习委员了,
    201. 又被选上了,所以她所得的经验会比我多一些。但渐渐的我发现了一个有趣的现象……
    202. 这位和我担任同样职位的人,名叫李鹂歌。她收作业从来不慌不忙,
    203. 这星期的作业可以收到下星期也没上交给班主任。我真的是挺佩服她的。
    204. 做事从来不紧不慢。因为当时我刚上任,也不太了解要做些啥,我只知道跟着李鹂歌做就行了。
    205. 但却没想到她收的作业,可以收那么久。
    206. 或许因为我当时刚上任,小组组长交作业都已经习惯交给李鹂歌了,记名也是她记,也够累的。
    207. 至于,其实现在也是这样。当时我只负责送作业,好轻松啊!
    208. 李鹂歌收作业慢慢吞吞,而我正好相反,今天做的作业,巴不得一来到学校就收齐交给班主任。
    209. 所以最近,一做完操我就开始向每一组的小组长催语文作业,没写完的也不等了,直接记名,
    210. 上报给班主任,没写完的下午留堂。所以,现在收的作业可以第一节课还没上就送到老师办公室。
    211. 但偶尔有时候,作业过多,收得乱七八糟,又有好多人没做作业,我们又记不过来,
    212. 经常有人浑水摸鱼就过了关。因为我渐渐发现,只要在第一节课上课之前没收完作业,
    213. 你就甭想再把作业收好。一下课大家都跑去疯玩了,教室里乱糟糟的。所以在第一节课上课之前,
    214. 我都会催组长交作业。再把镜头转向李鹂歌,人家正在优哉游哉的吃早餐呢,谁叫我不在学校吃,
    215. 在家里早早的就吃完了,不过,她也是有工作的,记名。有些交的慢的组长,直接把名字告诉我,
    216. 由我来汇报给李鹂歌,由李鹂歌来把名字填写在黑名单里。我怕忘了谁的名字,就一直再念,
    217. 没想到李鹂歌刚拿出本子就不紧不慢的说:“今天几号?”我一回答,把刚才记得名字全给忘了。
    218. '''
    219. handler = CrimeMining()
    220. handler.main(content8)

    2.ner模块,主要对文本进行ner和句意分析:

    1. import os
    2. from pyltp import Segmentor, Postagger, Parser, NamedEntityRecognizer
    3. class LtpParser():
    4. def __init__(self):
    5. LTP_DIR = "./ltp_data"
    6. cws_path = os.path.join(LTP_DIR, "cws.model")
    7. self.segmentor = Segmentor(cws_path)
    8. pos_path = os.path.join(LTP_DIR, "pos.model")
    9. self.postagger = Postagger(pos_path)
    10. parser_path = os.path.join(LTP_DIR, "parser.model")
    11. self.parser = Parser(parser_path)
    12. ner_path = os.path.join(LTP_DIR, "ner.model")
    13. self.recognizer = NamedEntityRecognizer(ner_path)
    14. '''ltp基本操作'''
    15. def basic_parser(self, words):
    16. postags = list(self.postagger.postag(words))
    17. netags = self.recognizer.recognize(words, postags)
    18. return postags, netags
    19. '''ltp获取词性'''
    20. def get_postag(self, words):
    21. return list(self.postagger.postag(words))
    22. '''基于实体识别结果,整理输出实体列表'''
    23. def format_entity(self, words, netags, postags):
    24. name_entity_dist = {}
    25. name_entity_list = []
    26. place_entity_list = []
    27. organization_entity_list = []
    28. ntag_E_Nh = ""
    29. ntag_E_Ni = ""
    30. ntag_E_Ns = ""
    31. index = 0
    32. for item in zip(words, netags):
    33. word = item[0]
    34. ntag = item[1]
    35. if ntag[0] != "O":
    36. if ntag[0] == "S":
    37. if ntag[-2:] == "Nh":
    38. name_entity_list.append(word+'_%s ' % index)
    39. elif ntag[-2:] == "Ni":
    40. organization_entity_list.append(word+'_%s ' % index)
    41. else:
    42. place_entity_list.append(word + '_%s ' % index)
    43. elif ntag[0] == "B":
    44. if ntag[-2:] == "Nh":
    45. ntag_E_Nh = ntag_E_Nh + word + '_%s ' % index
    46. elif ntag[-2:] == "Ni":
    47. ntag_E_Ni = ntag_E_Ni + word + '_%s ' % index
    48. else:
    49. ntag_E_Ns = ntag_E_Ns + word + '_%s ' % index
    50. elif ntag[0] == "I":
    51. if ntag[-2:] == "Nh":
    52. ntag_E_Nh = ntag_E_Nh + word + '_%s ' % index
    53. elif ntag[-2:] == "Ni":
    54. ntag_E_Ni = ntag_E_Ni + word + '_%s ' % index
    55. else:
    56. ntag_E_Ns = ntag_E_Ns + word + '_%s ' % index
    57. else:
    58. if ntag[-2:] == "Nh":
    59. ntag_E_Nh = ntag_E_Nh + word + '_%s ' % index
    60. name_entity_list.append(ntag_E_Nh)
    61. ntag_E_Nh = ""
    62. elif ntag[-2:] == "Ni":
    63. ntag_E_Ni = ntag_E_Ni + word + '_%s ' % index
    64. organization_entity_list.append(ntag_E_Ni)
    65. ntag_E_Ni = ""
    66. else:
    67. ntag_E_Ns = ntag_E_Ns + word + '_%s ' % index
    68. place_entity_list.append(ntag_E_Ns)
    69. ntag_E_Ns = ""
    70. index += 1
    71. name_entity_dist['nhs'] = self.modify_entity(name_entity_list, words, postags, 'nh')
    72. name_entity_dist['nis'] = self.modify_entity(organization_entity_list, words, postags, 'ni')
    73. name_entity_dist['nss'] = self.modify_entity(place_entity_list,words, postags, 'ns')
    74. return name_entity_dist
    75. '''entity修正,为rebuild_wordspostags做准备'''
    76. def modify_entity(self, entity_list, words, postags, tag):
    77. entity_modify = []
    78. if entity_list:
    79. for entity in entity_list:
    80. entity_dict = {}
    81. subs = entity.split(' ')[:-1]
    82. start_index = subs[0].split('_')[1]
    83. end_index = subs[-1].split('_')[1]
    84. entity_dict['stat_index'] = start_index
    85. entity_dict['end_index'] = end_index
    86. if start_index == entity_dict['end_index']:
    87. consist = [words[int(start_index)] + '/' + postags[int(start_index)]]
    88. else:
    89. consist = [words[index] + '/' + postags[index] for index in range(int(start_index), int(end_index)+1)]
    90. entity_dict['consist'] = consist
    91. entity_dict['name'] = ''.join(tmp.split('_')[0] for tmp in subs) + '/' + tag
    92. entity_modify.append(entity_dict)
    93. return entity_modify
    94. '''基于命名实体识别,修正words,postags'''
    95. def rebuild_wordspostags(self, name_entity_dist, words, postags):
    96. pre = ' '.join([item[0] + '/' + item[1] for item in zip(words, postags)])
    97. post = pre
    98. for et, infos in name_entity_dist.items():
    99. if infos:
    100. for info in infos:
    101. post = post.replace(' '.join(info['consist']), info['name'])
    102. post = [word for word in post.split(' ') if len(word.split('/')) == 2 and word.split('/')[0]]
    103. words = [tmp.split('/')[0] for tmp in post]
    104. postags = [tmp.split('/')[1] for tmp in post]
    105. return words, postags
    106. '''依存关系格式化'''
    107. def syntax_parser(self, words, postags):
    108. arcs = self.parser.parse(words, postags)
    109. words = ['Root'] + words
    110. postags = ['w'] + postags
    111. tuples = list()
    112. for index in range(len(words)-1):
    113. # print(arcs[index])
    114. # arc_index = arcs[index].head
    115. # arc_relation = arcs[index].relation
    116. arc_index = arcs[index][0]
    117. arc_relation = arcs[index][1]
    118. tuples.append([index+1, words[index+1], postags[index+1], words[arc_index], postags[arc_index], arc_index, arc_relation])
    119. # print(tuples)
    120. return tuples
    121. '''为句子中的每个词语维护一个保存句法依存儿子节点的字典'''
    122. def build_parse_child_dict(self, words, postags, tuples):
    123. child_dict_list = list()
    124. for index, word in enumerate(words):
    125. child_dict = dict()
    126. for arc in tuples:
    127. if arc[3] == word:
    128. if arc[-1] in child_dict:
    129. child_dict[arc[-1]].append(arc)
    130. else:
    131. child_dict[arc[-1]] = []
    132. child_dict[arc[-1]].append(arc)
    133. child_dict_list.append([word, postags[index], index, child_dict])
    134. return child_dict_list
    135. '''parser主函数'''
    136. def parser_main(self, words, postags):
    137. tuples = self.syntax_parser(words, postags)
    138. child_dict_list = self.build_parse_child_dict(words, postags, tuples)
    139. return tuples, child_dict_list
    140. '''基础语言分析'''
    141. def basic_process(self, sentence):
    142. words = list(self.segmentor.segment(sentence))
    143. postags, netags = self.basic_parser(words)
    144. name_entity_dist = self.format_entity(words, netags, postags)
    145. words, postags = self.rebuild_wordspostags(name_entity_dist, words, postags)
    146. return words, postags

    3.textrank模块:主要提取高频词和关键词

    1. import jieba.posseg as pseg
    2. from collections import defaultdict
    3. import sys
    4. '''textrank图算法'''
    5. class textrank_graph:
    6. def __init__(self):
    7. self.graph = defaultdict(list)
    8. self.d = 0.85 #d是阻尼系数,一般设置为0.85
    9. self.min_diff = 1e-5 #设定收敛阈值
    10. #添加节点之间的边
    11. def addEdge(self, start, end, weight):
    12. self.graph[start].append((start, end, weight))
    13. self.graph[end].append((end, start, weight))
    14. #节点排序
    15. def rank(self):
    16. #默认初始化权重
    17. weight_deafault = 1.0 / (len(self.graph) or 1.0)
    18. #nodeweight_dict, 存储节点的权重
    19. nodeweight_dict = defaultdict(float)
    20. #outsum,存储节点的出度权重
    21. outsum_node_dict = defaultdict(float)
    22. #根据图中的边,更新节点权重
    23. for node, out_edge in self.graph.items():
    24. #是 [('是', '全国', 1), ('是', '调查', 1), ('是', '失业率', 1), ('是', '城镇', 1)]
    25. nodeweight_dict[node] = weight_deafault
    26. outsum_node_dict[node] = sum((edge[2] for edge in out_edge), 0.0)
    27. #初始状态下的textrank重要性权重
    28. sorted_keys = sorted(self.graph.keys())
    29. #设定迭代次数,
    30. step_dict = [0]
    31. for step in range(1, 1000):
    32. for node in sorted_keys:
    33. s = 0
    34. #计算公式:(edge_weight/outsum_node_dict[edge_node])*node_weight[edge_node]
    35. for e in self.graph[node]:
    36. s += e[2] / outsum_node_dict[e[1]] * nodeweight_dict[e[1]]
    37. #计算公式:(1-d) + d*s
    38. nodeweight_dict[node] = (1 - self.d) + self.d * s
    39. step_dict.append(sum(nodeweight_dict.values()))
    40. if abs(step_dict[step] - step_dict[step - 1]) <= self.min_diff:
    41. break
    42. #利用Z-score进行权重归一化,也称为离差标准化,是对原始数据的线性变换,使结果值映射到[0 - 1]之间。
    43. #先设定最大值与最小值均为系统存储的最大值和最小值
    44. (min_rank, max_rank) = (sys.float_info[0], sys.float_info[3])
    45. for w in nodeweight_dict.values():
    46. if w < min_rank:
    47. min_rank = w
    48. if w > max_rank:
    49. max_rank = w
    50. for n, w in nodeweight_dict.items():
    51. nodeweight_dict[n] = (w - min_rank/10.0) / (max_rank - min_rank/10.0)
    52. return nodeweight_dict
    53. '''基于textrank图算法的关键词提取'''
    54. class TextRank:
    55. def __init__(self):
    56. self.candi_pos = ['n', 'v']
    57. self.stop_pos = ['nt']
    58. self.span = 5
    59. def extract_keywords(self, word_list, num_keywords):
    60. g = textrank_graph()
    61. cm = defaultdict(int)
    62. for i, word in enumerate(word_list):
    63. if word[1][0] in self.candi_pos and len(word[0]) > 1:
    64. for j in range(i + 1, i + self.span):
    65. if j >= len(word_list):
    66. break
    67. if word_list[j][1][0] not in self.candi_pos or word_list[j][1] in self.stop_pos or len(word_list[j][0]) < 2:
    68. continue
    69. pair = tuple((word[0], word_list[j][0]))
    70. cm[(pair)] += 1
    71. for terms, w in cm.items():
    72. g.addEdge(terms[0], terms[1], w)
    73. nodes_rank = g.rank()
    74. nodes_rank = sorted(nodes_rank.items(), key=lambda asd:asd[1], reverse=True)
    75. return nodes_rank[:num_keywords]

    4.生成图谱模块:利用前几个模块的结果,写进固定的html框架,具体参考echarts的js结构。

    1. '''创建展示页面'''
    2. class GraphShow():
    3. def __init__(self):
    4. self.base = '''
    5. '''
    6. '''读取文件数据'''
    7. def create_page(self, events):
    8. nodes = []
    9. for event in events:
    10. nodes.append(event[0])
    11. nodes.append(event[1])
    12. # print(nodes)
    13. node_dict = {node: index for index, node in enumerate(nodes)}
    14. # print(node_dict)
    15. data_nodes = []
    16. data_edges = []
    17. for node, id in node_dict.items():
    18. data = {}
    19. data["group"] = 'Event'
    20. data["id"] = id
    21. data["label"] = node
    22. data_nodes.append(data)
    23. for edge in events:
    24. data = {}
    25. data['from'] = node_dict.get(edge[0])
    26. data['label'] = ''
    27. data['to'] = node_dict.get(edge[1])
    28. data_edges.append(data)
    29. # print(data_nodes)
    30. # print(data_edges)
    31. self.create_html(data_nodes, data_edges)
    32. return
    33. '''生成html文件'''
    34. def create_html(self, data_nodes, data_edges):
    35. f = open('graph_show_02.html', 'w+',encoding='utf-8')
    36. # print('data_nodes',str(data_nodes))
    37. # print('data_edges',str(data_edges))
    38. html = self.base.replace('data_nodes', str(data_nodes)).replace('data_edges', str(data_edges))
    39. print(html)
    40. f.write(html)
    41. f.close()

    本文随机选用了网上的一篇文章text = '''身为一名学习委员,同学的作业要立马交了就立马送到老师办公室。因为我们是两个语文学习文员,但共同干同一件事——收全班同学的语文作业。当时竞选班长,我被选上当语文学习委员,而另一个同学曾经已经是语文学习委员了,又被选上了,所以她所得的经验会比我多一些。但渐渐的我发现了一个有趣的现象……这位和我担任同样职位的人,名叫李鹂歌。她收作业从来不慌不忙,这星期的作业可以收到下星期也没上交给班主任。我真的是挺佩服她的。做事从来不紧不慢。因为当时我刚上任,也不太了解要做些啥,我只知道跟着李鹂歌做就行了。但却没想到她收的作业,可以收那么久。或许因为我当时刚上任,小组组长交作业都已经习惯交给李鹂歌了,记名也是她记,也够累的。至于,其实现在也是这样。当时我只负责送作业,好轻松啊!李鹂歌收作业慢慢吞吞,而我正好相反,今天做的作业,巴不得一来到学校就收齐交给班主任。所以最近,一做完操我就开始向每一组的小组长催语文作业,没写完的也不等了,直接记名,上报给班主任,没写完的下午留堂。所以,现在收的作业可以第一节课还没上就送到老师办公室。但偶尔有时候,作业过多,收得乱七八糟,又有好多人没做作业,我们又记不过来,经常有人浑水摸鱼就过了关。因为我渐渐发现,只要在第一节课上课之前没收完作业,你就甭想再把作业收好。一下课大家都跑去疯玩了,教室里乱糟糟的。所以在第一节课上课之前,我都会催组长交作业。再把镜头转向李鹂歌,人家正在优哉游哉的吃早餐呢,谁叫我不在学校吃,在家里早早的就吃完了,不过,她也是有工作的,记名。有些交的慢的组长,直接把名字告诉我,由我来汇报给李鹂歌,由李鹂歌来把名字填写在黑名单里。我怕忘了谁的名字,就一直再念,没想到李鹂歌刚拿出本子就不紧不慢的说:“今天几号?”我一回答,把刚才记得名字全给忘了。'''

    结果如下:

    代码参考刘焕勇老师的项目,连接如下,Author: lhy

    textrank理论参考:

    TextRank算法学习及使用_潘多拉星系的博客-CSDN博客_textrank

  • 相关阅读:
    旧手机热点机改造成服务器方案
    java泛型的深入 泛型还可以在很多地方进行定义 泛型类 泛型方法 泛型接口 泛型的继承和通配符 泛型类练习
    Nature Microbiology | SeqCode:基于序列数据描述的原核生物命名规则
    KMP算法
    spring实战笔记
    互联网金融P2P主业务场景自动化测试
    小程序员 scroll滚动与页面滚动冲突造成快速滑到底部卡顿失败问题
    备战9月9日C/C++青少年等级考试(1~8级)
    DP读书:开源软件的影响力(小白向)解读Embedded_SIG介绍以及代码架构解析
    基于SSM的学院就业信息网设计与实现
  • 原文地址:https://blog.csdn.net/L_goodboy/article/details/127731689