编译器:Anaconda3里的spyder(python3.7)编译器
事先要确定编译器里有这几个库:urllib,bs4,jieba,os,math,heapq,Bio,numpy
这个程序是以爬取观察者网上的部分新闻为例。
jieba库的基本用法: https://github.com/fxsjy/jieba
停用词表:https://blog.csdn.net/shijiebei2009/article/details/39696571
TD-IDF值计算的参考文档:https://blog.csdn.net/sangyongjia/article/details/52440063
使用Bio库里的kcluster函数进行K-Means算法的基础讲解:https://biopython-cn.readthedocs.io/zh_CN/latest/cn/chr15.html#uncentered-correlation
代码里的文件文件路径是我自己电脑上的路径,大家在复制代码去自己计算机上测试的时候别忘了改文件路径。
之前是选用的另一个库里的一个K-Means算法函数,但是那个函数默认是使用欧氏距离来计算点之间的距离,并且没法修改,而这个函数有多种计算距离的公式可供使用,更加的灵活,强烈推荐使用。
基本每一行代码我都有写注释,这里就不对代码本身做过多的讲解了(其实是因为我懒),大家自己看吧~
其实我感觉用K-Means算法来对文本进行分类的效果不是很好,因为无法计算分类的准确率啦,也不知道该分成多少类好啊,如果有时间的话,我之后再用朴素贝叶斯算法再做一遍。
有问题欢迎讨论(时间短的话我可能还能回答,过一段时间可能我自己都忘了是怎么做的了)
下面是代码,复制到自己的编译器上即可使用。
import urllib.request as eq
from bs4 import BeautifulSoup
import jieba
import os
import math
import heapq
from Bio.Cluster import kcluster
import numpy
#爬虫程序段
def pachong():#爬虫程序段
biaoqian=[]
list1=[]#设置一个列表来存放链接
url='https://www.guancha.cn//'#抓取的网址
p=1
req=eq.Request(url=url)#创建Request对象
#设置访问网页时的信息头,将自己伪装成一个正常的浏览器访问
req.add_header("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4098.3 Safari/537.36")
data = eq.urlopen(url).read()#将网页源代码放在变量data中
soup = BeautifulSoup(data, "lxml")#将data变量中的网页源代码整理了一下储存在soup变量中
#tmp1=soup.find_all('h4',class_='module-title')#将所有‘h4’中class='module-title'的标签取出来
tmp=soup.find_all('div',class_='resemble-art c_hidden')#将所有‘div’中class='resemble-art c_hidden'的标签取出来
for i in tmp:#将所有该标签下的链接取出来
start=str(i).find('a href="')#返回这段文字匹配到的第一个字符的位置
end=str(i).find('" target="_blank"')#返回这段文字的第一个字符位置
a=str(i)[start+8:end]#取字符串的一部分
biaoqian.append(a)
list1.append('https://www.guancha.cn'+a)
for j in list1:
rurl=j
req=eq.Request(url=rurl)#创建Request对象
#设置访问网页时的信息头,将自己伪装成一个正常的浏览器访问
req.add_header("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4098.3 Safari/537.36")
data = eq.urlopen(rurl).read()#将网页源代码放在变量data中
soup = BeautifulSoup(data, "lxml")#将data变量中的网页源代码整理了一下储存在soup变量中
a=soup('p')
dizhi="D:/学习/数据挖掘与机器学习/爬虫下载文件位置/观察者网"+str(p)+".txt"
wenjian=open(dizhi, "w+",encoding='utf-8')#打开一个可读写文件
k=0
while k
wenjian.write("".join(a[k].text.split()))#把文本写入文件中,"".join(a[k].text.split()):去除文本中的空格和换行符
k=k+1
wenjian.close()
p+=1
return biaoqian;
#加载停用词
def tinyongci():
tyc=[]
tyc_wj=open("D:/学习/数据挖掘与机器学习/停用词.txt", "r",encoding='utf-8').read()#该行代码在使用时应把停用词的路径修改为自己电脑上的路径
str1=''
for i in tyc_wj:#遍历文档里的字符
if i in '\n':#换行符在txt文本中被当做间隔符,遇到换行符说明str1中存放的是一个完整的停用词了
tyc.append(str1)#将str1中的停用词添加到tyc列表中
str1=''#重置str1
else:
str1=str1+i#如果不是换行符就说明该字符是停用词的一部分,将其添加进str1中
tyc.append(str1)#将最后一个停用词添加进tyc列表中
return tyc
#结巴分词
def jiebafenci():
list1=[]
list_name=[]
txt=''
counts = {} # 通过键值对的形式存储词语及其出现的次数
for i in os.listdir("D:/学习/数据挖掘与机器学习/爬虫下载文件位置"):
list_name.append(i)#读取该文件夹内的所有文件名字
for i in list_name:
dizhi="D:/学习/数据挖掘与机器学习/爬虫下载文件位置/"+str(i)
wenjian=open(dizhi, "r",encoding='utf-8')#用只读的模式打开文件
txt=txt+wenjian.read()
words = jieba.lcut(txt)#使用精确模式对文本进行分词
for word in words:#去除列表中的停用词
if len(word) == 1: # 单个词语不计算在内
continue
elif (tyc.count(word) == 1):#停用词不计算在内
continue
else:
counts[word] = counts.get(word, 0) + 1 # 遍历所有词语,每出现一次其对应的值加 1
items = list(counts.items())#返回一个元组类型的字典键值对,再转化为列表
items.sort(key=lambda x: x[1], reverse=True) # 根据词语出现的次数进行从大到小排序
for i in range(len(items)):
list1.append(items[i][0])
return list1
#IF_IDF矩阵
def IF_IDF():
list2=[]
list3=[]
list_name=[]
for i in os.listdir("D:/学习/数据挖掘与机器学习/爬虫下载文件位置"):
list_name.append(i)#读取该文件夹内的所有文件名字
for i in list_name:
dizhi="D:/学习/数据挖掘与机器学习/爬虫下载文件位置/"+str(i)
wenjian=open(dizhi, "r",encoding='utf-8')#用只读的模式打开文件
words = jieba.lcut(wenjian.read())#使用精确模式对文本进行分词
counts={}
counts=counts.fromkeys(list1, 0)#建立一个用来计算词语出现次数的字典
for word in words:
if word in counts:
counts[word]+=1# 遍历所有词语,每出现一次其对应的值加 1
list3=[]
for j in counts:
list3.append(counts[j])#将字典中的值赋值给列表
list2.append(list3)#做一个嵌套列表用来存放每篇文章中词语出现次数
return list2
#求每篇文章中词频最高的词
def ci_benwen():
list3=[]
for i in range(len(list2)):
list3.append(list1[list2[i].index(max(list2[i]))])
return list3
#找出所有文章中TF-IDF值前五大的词
def ci_quanbu():
tf=[]
idf=[]
tf_idf=[]
d=len(list2)
list5=[]
list9=[]
for i in range(len(list2)):#用来算出tf(频率)的值
list4=[]
for j in range(len(list2[i])):
list4.append(list2[i][j]/(sum(list2[i])+1))#计算频率的公式
tf.append(list4)
for i in range(len(list2[0])):#算idf的值
list5.append(0)
for j in range(len(list2)):
if list2[j][i]>0:
list5[i]+=1#求某个词在几篇文章中出现过
idf.append(math.log(d/list5[i]))#算idf的公式
for i in range(len(list2)):#计算tf-idf的值
list6=[]
for j in range(len(list2[i])):
list6.append(idf[j]*tf[i][j])#两两相乘得出tf-idf的值
tf_idf.append(list6)
list7=list(numpy.max(tf_idf,axis=0))#取出每个词的最大tf-idf值
list8=heapq.nlargest(5, list7)#找出tf-idf最大的五个数值
for i in list8:
list9.append(list1[list7.index(i)])#将数值对应的词存入list9列表中
return tf_idf,list9
def k_means():
print('\nStart Kmeans:')
'''这个函数的返回值为一个包含 (clusterid, error, nfound) 的元组,
其中 clusterid 是 一个整型矩阵,为每行或列所在的类。
error 是最优聚类解中,每类内距离的总和, nfound 指的是最优解出现的次数。'''
clusterid, error, nfound = kcluster(tf_idf,dist='u')#Bio库中使用kmeans算法的结果;u表示使用余弦相似度算法
#每个样本所属的簇
print(clusterid)
i = 1
while i <= len(clusterid):
print(i, clusterid[i-1])
i = i + 1
return clusterid, error, nfound
if __name__ == '__main__':
tyc=tinyongci()#加载常用的停用词
biaoqian=pachong()#爬虫程序段
list1=jiebafenci()#list1存放的是整篇文章中73个高频率词
list2=IF_IDF()#list2是tf-idf矩阵
list3=ci_benwen()#list3存放的是每篇文章中的最高频的词
print('每篇文章中的最高频的词:')
for i in range(len(list3)):
print(i+1,list3[i])
tf_idf,list9=ci_quanbu()#tf_idf存放的是每个词的tf_idf数值;list9存放的是tf_idf最大的五个词
print('\ntf_idf最大的五个词:')
for i in range(5):
print(i+1,list9[i])
clusterid, error, nfound = k_means()#使用kmeans算法