本帖最后由 为人生而奋斗 于 2019-10-15 16:19 编辑
结巴分词在SEO中可以应用于分析/提取文章关键词、关键词归类、标题重写、文章伪原创等等方面,用处非常多。
具体结巴分词项目:https://github.com/fxsjy/jieba
安装方法:
以mac系统为例(因为自己用mac系统):
在终端输入:
[Asm] 纯文本查看 复制代码pip3 install jieba -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
image.png (138.97 KB, 下载次数: 0)
2019-10-15 10:48 上传
这样就安装完成,然后就可以用coderunner软件开始写python3使用了
常用方法使用示例
1. 分词常用方法
jieba.cut 方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型
jieba.cut_for_search 方法接受两个参数:需要分词的字符串;是否使用 HMM 模型。该方法适合用 于搜索引擎构建倒排索引的分词,粒度比较细 待分词的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建议直接输入 GBK 字符串, 可能无法预料地错误解码成 UTF-8
jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定义分词器,可用于同时使用不同词典。 jieba.dt 为默认分词器,所有全局分词相关函数都是该分词器的映射。(一般使用默认的就可以了)
代码测试:
[Asm] 纯文本查看 复制代码#!/usr/bin/env python3# -*- coding: utf-8 -*-
import jieba
ret1 = jieba.cut('我来到北京清华大学', cut_all=True)
ret2 = jieba.cut('我来到北京清华大学', cut_all=False)
ret3 = jieba.cut_for_search('我来到北京清华大学')
print('/'.join(ret1))
print('/'.join(ret2))
print('/'.join(ret3))
image.png (402.44 KB, 下载次数: 0)
2019-10-15 10:50 上传
开始应用:
分类海量关键词(用于专题页、tag标签等)
假如我们用之前的关键词挖掘工具挖掘出了一堆关键词,看起来不仅杂乱无章,并且还要花大量的时间来进行过滤和归类。那么,就教大家用结巴分词来对关键词进行归类,几千个关键词1秒完成,几万关键词1分钟也能搞定。最后可以得到下图两种结果。这个可以用来干嘛呢?我们在做SEO的时候是不是可以根据分类将同一类的词做成专题页或者tag标签的聚合页?
第一种:json格式
第二种:Excel 格式
提取文章关键词
假如我们需要了解一篇文章内,关于该行业的关键词的表现如何(文章中包含了多少关键词,TF_IDF值是多 少,或者是TextRank的值是多少)等,我们都需要对文章进行分词处理,但是由于每个行业都有自己的专业 名词,所以仅仅使用python默认的词典的话那么就很难获取到准确的数据,数据得出来也不是我们想要的。 这个时候一般的做法就是添加自己的行业关键词字典,让结巴分词更准确。
主要步骤:
找到行业的相关关键词,保存到TXT文件里面
将所有的词都设置为相同的自定义词性,比如kws
在程序中导入自定义词典
使用TF-IDF算法提取文章的关键词,在词性过滤参数里面添加自定义词性,打印结果分析行业词的情 况。
该方法在实际用得比较少,主要就分析一下竞争对手内容中关键词的部署情况,实际的参考意义对于SEO来说 不是很大。
二、关键词归类|标题重写|文章伪原创
通过余弦相似度算法计算两个字符串之间的相关度,来对关键词进行归类、重写标题、文章伪原创等功能, 让你目瞪口呆。以下案例使用的母词文件均为txt文件,两种格式:一种内容是纯关键词的txt,每行一个关键词就好;另一种是关键词加指数的txt,关键词和指数之前用tab键分隔,一行一对关键词。
余弦相似度算法实现
[Asm] 纯文本查看 复制代码# -*- coding: utf-8 -*-from jieba import posseg
import math
import time
def simicos(str1, str2):
# 对两个要计算的字符串进行分词, 使用隐马尔科夫模型(也可不用)
# 由于不同的分词算法, 所以分出来的结果可能不一样
# 也会导致相似度会有所误差, 但是一般影响不大
cut_str1 = [w for w, t in posseg.lcut(str1) if 'n' in t or 'v' in t]
cut_str2 = [w for w, t in posseg.lcut(str2) if 'n' in t or 'v' in t]
# 列出所有词
all_words = set(cut_str1 + cut_str2)
# 计算词频
freq_str1 = [cut_str1.count(x) for x in all_words]
freq_str2 = [cut_str2.count(x) for x in all_words]
# 计算相似度
sum_all = sum(map(lambda z, y: z * y, freq_str1, freq_str2))
sqrt_str1 = math.sqrt(sum(x ** 2 for x in freq_str1))
sqrt_str2 = math.sqrt(sum(x ** 2 for x in freq_str2))
return sum_all / (sqrt_str1 * sqrt_str2)
if __name__ == '__main__':
case1 = "SEO"
case2 = "SEO培训网"
start = time.time()
similarity = simicos(case1, case2)
end = time.time()
print()
print("耗时: %.3fs" % (end - start))
print("相似度: %.3f" % similarity)
image.png (531.48 KB, 下载次数: 0)
2019-10-15 10:53 上传
结果:
[Asm] 纯文本查看 复制代码耗时: 0.751s相似度: 0.707
相似度在0.707,说明“SEO” 和“SEO培训网”这两个词相似度还是很高的。
2.关键词自动归类实现
实现思路:
将所有待分类的关键词放入到一个TXT文件中,程序将所有关键词读取到列表里面
将第一个词作为母词分别与其它词进行相似度计算,相似度大于0.3的就认为与该词同类。将对他 们放到一个新的列表中,并从原来的关键词列表中删除。
直到该词与列表中所有的词计算完毕,然后接着重复以上的操作,直到所有的词分类完毕。
算法缺陷:由于需要多次进行循环计算,因此时间复杂度比较高。不利于大批量的关键词快速归类, 而且如果关键词越驳杂,那么得到的分类就越多。
具体实现代码:
[Asm] 纯文本查看 复制代码# -*- coding: utf-8 -*-from jieba import posseg
import math
import json
import time
# 结果保存字典
result = {}
# Cache 缓存
cache = {}
def simicos(str1, str2):
"""
字符串余弦相似度算法实现, 添加缓存存储,减少分词带来的时间消耗
提高计算效率
:param str1: 要比较的字符串1
:param str2: 要比较的字符串2
:return: 相似度值0.0-1.0
"""
global cache
if cache.get(str1): # 或者用key in cache 方法也可以
cut_str1 = cache[str1]
else:
cut_str1 = [w for w, t in posseg.cut(str1) if 'n' in t or 'v' in t]
cache[str1] = cut_str1
if cache.get(str2):
cut_str2 = cache[str2]
else:
cut_str2 = [w for w, t in posseg.cut(str2) if 'n' in t or 'v' in t]
cache[str2] = cut_str2
all_words = set(cut_str1 + cut_str2)
freq_str1 = [cut_str1.count(x) for x in all_words]
freq_str2 = [cut_str2.count(x) for x in all_words]
sum_all = sum(map(lambda z, y: z * y, freq_str1, freq_str2))
sqrt_str1 = math.sqrt(sum(x ** 2 for x in freq_str1))
sqrt_str2 = math.sqrt(sum(x ** 2 for x in freq_str2))
try:
return sum_all / (sqrt_str1 * sqrt_str2)
except ZeroDivisionError:
return 0.0
def calculate(keyword_list):
"""
使用递归的方式进行计算和分类
优点:代码简单,容易理解
缺点:python默认最大的递归深度为1000,超过之后就会出错
:param keyword_list: 要分类的关键词列表
:return: None
"""
filter_word = []
# 获取第一个词作为母词
muci = keyword_list.pop(0)
# 用该词作为分类
result[muci] = []
print(len(keyword_list))
while keyword_list:
# 提取列表中的下一个词
kw = keyword_list.pop(0)
simi = simicos(muci, kw)
if simi >= 0.3:
result[muci].append(kw)
else:
filter_word.append(kw)
# 如果列表中还有词,就递归计算
if filter_word:
calculate(filter_word)
def classify(keyword_list):
"""
使用while循环的方法计算和分类
:param keyword_list: 要分类的关键词队列
:return: None
"""
muci = keyword_list.pop(0) # 第一个词
result[muci] = {"total": 0, "list": []}
last = keyword_list[-1] # 最后一个词
total_classify = 0
remain = len(keyword_list)
while keyword_list:
# 提取列表中的下一个词
kw = keyword_list.pop(0)
simi = simicos(muci, kw)
if simi >= 0.3:
result[muci]["list"].append(kw)
result[muci]["total"] += 1
remain -= 1
else:
keyword_list.append(kw)
if kw == last and keyword_list: # 如果已经是最后一个了
total_classify += 1
print("Has been classified %d, remain %d" % (total_classify, remain))
muci = keyword_list.pop(0)
remain -= 1
result[muci] = {"total": 0, "list": []}
if keyword_list:
last = keyword_list[-1]
else:
break
def result_filter(result_dict, bigthan=10):
"""
结果过滤筛选函数
由于使用该方法会等到很多的分类,有些分类是没有关键词的或者只有少数的相关词
那么对于这些分类就可能不需要了,我们就直接把他们过滤掉就好了
:param result_dict: 要筛选的分类结果
:param bigthan: 相关词数量大于等于该数的分类将保存
:return: 过滤后的结果
"""
retfilter = {}
for item, values in result_dict.items():
if values["total"] > bigthan:
retfilter[item] = values
return retfilter
if __name__ == "__main__":
t_start = time.time()
print("start....")
keywords = [key.strip() for key in open("baidumobilekey.txt", encoding='utf-8')]
classify(keywords)
filtered = result_filter(result)
# 结果保存在json中
f = open("result3.json", "w", encoding='utf-8')
f.write(json.dumps(filtered, ensure_ascii=False))
f.close()
print("done, consume %.3f" % (time.time() - t_start))
结果:
结果保存为json文件
因为上面的算法都是通过纯python写的,因此算法的速度是比较慢的,经测试,几万的关键词可能都需要十几分 钟,因此的话不适宜用来分类大量的关键词,同时如果要求的相似度越高,那么得出来的分类就越多。因此也不是 很好的一种解决办法。
还有一种就是使用编辑距离的算法,这个算法有别人用c语言写好的,而且不用分词,因此速度上比上面的算法会快很多,但是分类效果没那么好。一些不相关的词也可能会被分类到同一个分类下。
使用Levenshtein模块分类
代码实现: 需要安装Levenshtein模块,安装方法 pip install python-Levenshtein
[Asm] 纯文本查看 复制代码# -*- coding: utf-8 -*-import json
import time
import Levenshtein
result = {}
def classify(keyword_list):
"""
使用while循环的方法计算和分类
:param keyword_list: 要分类的关键词队列
:return: None
"""
muci = keyword_list.pop(0) # 第一个词
result[muci] = {"total": 0, "list": []}
last = keyword_list[-1] # 最后一个词
total_classify = 0
remain = len(keyword_list)
while keyword_list:
# 提取列表中的下一个词
kw = keyword_list.pop(0)
simi = Levenshtein.jaro_winkler(kw, muci)
if simi >= 0.8:
result[muci]["list"].append(kw)
result[muci]["total"] += 1
remain -= 1
else:
keyword_list.append(kw)
if kw == last and keyword_list: # 如果已经是最后一个了
total_classify += 1
print("Has been classified %d, remain %d" % (total_classify, remain))
muci = keyword_list.pop(0)
remain -= 1
result[muci] = {"total": 0, "list": []}
if keyword_list:
last = keyword_list[-1]
else:
break
def result_filter(result_dict, bigthan=10):
"""
结果过滤筛选函数
由于使用该方法会等到很多的分类,有些分类是没有关键词的或者只有少数的相关词
那么对于这些分类就可能不需要了,我们就直接把他们过滤掉就好了
:param result_dict: 要筛选的分类结果
:param bigthan: 相关词数量大于等于该数的分类将保存
:return: 过滤后的结果
"""
retfilter = {}
for item, values in result_dict.items():
if values["total"] > bigthan:
retfilter[item] = values
return retfilter
if __name__ == "__main__":
t_start = time.time()
print("start....")
keywords = [key.strip() for key in open("baidumobilekey.txt", encoding='utf-8')]
# keywords = [key.strip() for key in open("004.txt", encoding='utf-8')]
# calculate(keywords)
classify(keywords)
filtered = result_filter(result)
# 结果保存在json中
f = open("result4.json", "w", encoding='utf-8')
f.write(json.dumps(filtered, ensure_ascii=False))
f.close()
print("done, consume %.3f" % (time.time() - t_start))
得到的结果也是一个json文件。
结巴分词关键词分类
以上的算法速度是快了,但是的话效果也不是很好,而且分类也比较多。
这里还有一种比较折中的办法,那就是通过结巴将所有的关键词进行分词,然后根据TF-IDF算法,提取出里面前N 个名词或动词作为分类。然后根据包含的方式将所有的关键词归类。
该方法可以快速的将大量的关键词归类,但是会有一部分的关键词是获取不到归类的。至于选择哪种方式,由自己决定。
具体代码:
[Asm] 纯文本查看 复制代码# -*- coding: utf-8 -*-"""
python结巴关键词分类脚本,算法二
1. 通过TF_IDF算法提取出前N个词性的词作为分类
2. 遍历整个关键词列表,假如关键词中包含分类名,则将词放入到分类中
3. 如果都没有,则将词放入到其它分类
"""
import codecs
import csv
import time
from jieba import analyse
result = {}
def init(group):
for g in group:
result[g] = {"total": 0, "keys": []}
result["其它"] = {"total": 0, "keys": []}
def classsify(kw_list, group):
index = 0
total = len(kw_list)
while index < total:
flag = 0
for g in group:
if g in kw_list[index][0]:
flag = 1
result[g]["total"] += int(keyword_list[index][1])
result[g]["keys"].append(kw_list[index])
if not flag:
result["其它"]["total"] += int(keyword_list[index][1])
result["其它"]["keys"].append(kw_list[index])
index += 1
def write_to_file(group):
savefile = open("result.csv", "w", encoding='utf-8')
csvwriter = csv.writer(savefile)
fields = []
group.append("其它")
for g in group:
fields.append(g)
fields.append(result[g]["total"])
csvwriter.writerow(fields)
maxline = max(len(item["keys"]) for item in result.values())
cols = len(fields)
for row in range(maxline):
rowfield = ["" for _ in range(cols)]
gix = 0
kwitem = []
for col in range(cols):
if result.get(group[gix])["keys"]:
if col % 2 == 0:
kwitem = result.get(group[gix])["keys"].pop(0)
rowfield[col] = kwitem[0]
if col % 2 == 1:
gix += 1
rowfield[col] = kwitem[1]
csvwriter.writerow(rowfield)
savefile.close()
if __name__ == "__main__":
print("start.....")
t_start = time.time()
keyword_list = [k.strip().split('\t') for k in open("003.txt", encoding='utf-8')]
groups = analyse.extract_tags(" ".join(item[0] for item in keyword_list),
topK=20, allowPOS=('ns', 'n', 'vn', 'v', 'nr'))
groups = [g for g in groups]
init(groups)
classsify(keyword_list, groups)
write_to_file(groups)
print("done, consume %.3f" % (time.time() - t_start))
结果:每一列为一个类别,例如第一列是“考研”这个类别的所有词语分类。
结果存为Excel 格式