目录
实验原理:
实验准备:
实验步骤与内容:
参考代码:
运行结果:
- 学习网络爬虫常用工具包 requests,以及对网页解析工具 BeautifulSoup 等操作;
- 依托自然语言处理领域的文本数据处理任务,学习常用的中文文本加工工具,实现对数据集的分词、词频统计、以及词云显示操作;
- 熟悉掌握安装和使用各种文本处理 python 库的方法;
- 熟练掌握条件语句;
- 熟练使用字典等数据类型。
实验原理:
1.网络爬虫
网络爬虫又称网络蜘蛛、网络机器人,它是一种按照一定的规则自动浏览、检索网页信息的程序或者脚本。网络爬虫能够自动请求网页,并将所需要的数据抓取下来。通过对抓取的数据进行处理,从而提取出有价值的信息。
我们所熟悉的一系列搜索引擎都是大型的网络爬虫,比如百度、搜狗、360 浏览器、谷歌搜索等等。每个搜索引擎都拥有自己的爬虫程序,比如 360 浏览器的爬虫称作 360Spider,搜狗的爬虫叫做 Sogouspider。
爬虫是一把双刃剑,它给我们带来便利的同时,也给网络安全带来了隐患。有些不法分子利用爬虫在网络上非法搜集网民信息,或者利用爬虫恶意攻击他人网站,从而导致网站瘫痪的严重后果。关于爬虫的如何合法使用,推荐阅读《中华人民共和国网络安全法》。
2.文本处理
自然语言处理(Natural Language Processing, NLP)研究的是能实现人与计算机之间用自然语言进行有效通信的各种理论和方法,主要应用于机器翻译、文本分类、问题回答、文本语义对比等方面。通常,在进行深入的 NLP 分析任务之前,会先对文本进行预处理,即对预先准备好的文本进行基本的分析和变换, 以留下更有用的文本数据。文本预处理的流程如图 1 所示,通常包含获取原始文本、分词、文本清洗、标准化等,顺序可有不同。
图 1 文本处理流程
1)分词
分词就是将句子、段落、文章这种长文本,分解为以字词为单位的数据结构, 方便后续的处理分析工作。由于字的粒度太小,无法表达完整含义,而句子的粒度太大、承载的信息量多,很难复用,因此,词是一个比较合适的粒度。词是表达完整含义的最小单位。
中英文在分词上,由于语言的特殊性导致分词的思路也会不一样。大多数情况下,英文直接使用空格就可以进行分词。但对中文来说,如何切分是一个难点, 且中文中一词多意的情况非常多,很容易出现歧义。另外中文需要不同的场景和要求选择不同的粒度。
2)文本清洗
由于大多数情况下,我们准备好的文本里都有很多无用的部分,例如爬取来的一些 HTML 代码、CSS 标签等,或者不需要用的标点符号、停用词等,需要分步骤去清洗。一些常用的清洗方法包括:去除空格、去除标点符号、英文大小写转换、中文繁简体转换、数字归一化、去除停用词/低频词、去除不必要的标签等。
3)标准化
对于英文来说,文本需要进行标准化,又称归一化。包括词干提取(stemming) 和词形还原(lemmatization)。
词干提取是删除词缀的过程(包括前缀、后缀、中缀、环缀),从而得到单词的词干。主要是采用“缩减”的方法,将词转换为词干,如将“cats”处理为“cat”, 将“effective”处理为“effect”。词干提取的结果可能并不是完整的、具有意义的词, 而只是词的一部分,如“revival”词干提取的结果为“reviv”,“ailiner”词干提取的结果为“airlin”。词干提取更多被应用于信息检索领域,如 Solr、Lucene 等,用于扩展检索,粒度较粗。
词形还原与词干提取相关,不同的是,词形还原更为复杂,不仅要进行词缀的转化,还要进行词性识别,区分相同词形但原形不同的词的差别,能够捕捉基于词根的规范单词形式。主要采用“转变”的方法,将词转变为其原形,如将“drove” 处理为“drive”,将“driving”处理为“drive”。词形还原处理后获得的结果是具有一定意义的、完整的词,一般为词典中的有效词。词形还原主要被应用于文本挖掘、自然语言处理,用于更细粒度、更为准确的文本分析和表达。
实验准备:
1.网络爬虫工具
(1)requests
文档自行学习快速上手 — Requests 2.18.1 文档 (python-requests.org)
(2)BeautifulSoup
文档自行学习 Beautiful Soup 4.4.0 文档 — Beautiful Soup 4.2.0 中文文档
2.文本处理工具
目前主流的中文处理工具有 Stanford CoreNLP、LTP(哈工大)、JIEBA、THULAC(清华大学)、ICTCLAS(中科院)等,英文工具有 Spacy、Gensim、NLTK 等。不同的中文词法分析软件结果差别不大,在不同数据集上的表现互有高低。下面介绍几种常用工具。
(1)Stanford CoreNLP
Stanford CoreNLP 是斯坦福大学自然语言处理小组开发的自然语言分析工具集,包含分句、分词、词性标注、命名实体识别、句法分析、指代消解等功能, 这些工具采用流式(pipeline)集成方式,提供单独的包下载,高度灵活且可扩展性强。Stanford CoreNLP 支持英文、中文、法文、德文以及西班牙文等。该工具包采用 Java 语言开发,支持 Java。提供 jar 包下载,便于集成到 Java 代码中,同时也支持 C#,Node.js,PHP,Python 等语言调用。
Stanford CoreNLP 的分词和命名实体识别工具是基于条件随机场模型实现的,而词性标注则是基于双向依存网络模型。
官网下载地址:https://stanfordnlp.github.io/CoreNLP/index.html 演示地址:http://corenlp.run/
在线演示:
图 2 Stanford CoreNLP 在线演示
该平台无需注册,在线版本已经集成到演示平台,处理时需要选择语言。stanfordcorenlp 是一个对 Stanford CoreNLP 进行了封装的 Python 工具包,下载安装后可以在 python 环境下直接调用。
(2)清华大学词法分析器(THU Lexical Analyzer for Chinese,THULAC)
THULAC 由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,具有中文分词和词性标注功能。THULAC 工具包随包附带的分词模型 Model_1 以及分词和词性标注模型 Model_2 是由人民日报语料库训练得到的,所以支持单独调用分词接口,但不能单独调用词性标注接口。语料库包含已标注的字数约为五千八百万字,你可以填写申请表来得到全部语料库。
THULAC 完全开源,公布了算法源代码、算法模型甚至语料库。官网介绍地址:THULAC:一个高效的中文词法分析工具包
在线演示地址:http://thulac.thunlp.org/demo
下载地址:
http://thulac.thunlp.org/#%E8%8E%B7%E5%8F%96%E9%93%BE%E6%8E%A5
词性标记集:
在线演示:
图 3 THULAC 在线演示
Thulac 是一个发布在 Pip 上的 Python 工具包(无须下载),安装后可通过import thulac 来引用,同时还提供 C++接口使用和按照命令格式运行可执行 jar 包完成分词和词性标注;在线系统已经部署在集成平台上。
实验步骤与内容:
1.安装工具包
对于requets 和Beatiful Soup 库,使用 pip install 安装requests 和beautifulsoup4
工具包。
常用的中文文本加工工具包主要有 JIEBA、Stanford CoreNLP 等,他们在不同数据集上的性能表现互有高低。对于 JIEBA 和 THULAC,使用 pip install 安装 jieba 和 thulac 工具包即可。
2.数据下载
创建 python 文件 python7/spider.py,使用 requests 和 beautifulsoup 工具包爬取豆瓣电影 top250(URL)的电影信息。电影信息包含电影名、类型。将该信息以 json 形式存到 movie.json 文件中。
例如:
[{
‘name’: ‘大闹天宫’,
‘type’: [‘剧情’,’动画’,’奇幻’,’古装’]
},
{
‘name’:‘ 教 父 2’, ‘type’:[‘剧情’,’犯罪’]
}]
图 4 movie.json 文件
图 5 comments.txt 文件
Note:对于电影名存在多个,只记录出现的第一个。
然后从这 250 个电影随机选择一部电影,然后爬取 20 条电影影评,保存到comments.txt 文件中。评论 url:https://movie.douban.com/subject/{电影 id 需要自己观察}/comments
3.分词、词性标注
为了更方便的使用上面所列加工工具,我们需要将 JIEBA、THULAC(清华大学)等分别集成到一个文本处理命令行文件中,包括两个 python 文件
(python7/Segment.py 和 python7/SegText.py,运行时须有 python3 环境,且已经安装了上述所列的包),Segment.py 可以针对单句文本进行处理,显示结果如下图 6 所示:
图 6 Segment.py 运行截图
Note: 如 果 使 用 THULAC 库 出 现 下 图 错 误 , 只 需 要 将thulac\character\CBTaggingDecode.py 中 第 170 行 的 start=time.clock() 替 换 成start=time.perf_counter()
SegText.py 可以针对整个文本文件进行处理,将会在输入文件同一文件夹下生成一个输出文件。其中 SegText.py 测试文件为数据下载中的电影评论comments.txt 文件。显示结果如下图 7 所示:
图 7 (a) Segtext.py 运行截图
图 7 (b) Segtext.py 运行输出数据
4.词频统计
创建 WordCount.py,计算输入文本的词频,如下图 8 所示。
图 8. WordClount.py 运行,分词情况
5.词云显示
建立 Word_Cloud.py 文件,利用 wordcloud 包(可自行安装)对 comments.txt 文件自动生成词云,并将其以图片的形式保存在当前文件夹。对于分词工具从jieba 和 thulac 两种工具包任意选择一种,生成结果如图 9(参考样例)所示:
图 9. Word_Cloud.py 运行生成的图片文件
参考代码:
#spider.py
import json
import requests # 发送请求
import random
from bs4 import BeautifulSoup # 解析网页
movie_infos=[]#存放电影的信息
movie_comments=[]#存放电影评论链接
url="https://movie.douban.com/top250"
def getmovieinfo(url,headers,file):
with open(file, 'w+', encoding='utf-8') as f: # 写入json文件
r = requests.get(url,headers=headers)#向豆瓣电影网页发送请求
# list_data = r.json()
soup = BeautifulSoup(r.text, 'html.parser')#利用BeautifulSoup库解析响应页面
for i in range(10):
url = "https://movie.douban.com/top250?start={}".format(str(i * 25))
r = requests.get(url, headers=headers) # 向豆瓣电影网页发送请求
# list_data = r.json()
soup = BeautifulSoup(r.text, 'html.parser') # 利用BeautifulSoup库解析响应页面
for movie in soup.select('.item'):
name = movie.select('.hd a')[0].tt.replace('\n', '').split('/')[0].strip('\xa0') # 电影名称(只取第一个) class hd a标签
# movie_name.append(name)
infos = movie.select('.bd p')[0].tt.strip() # 获取 导演 主演 年份 类型
type = infos.split('\n')[1].split('/')[2].strip().split(' ') # 获取类型
# movie_type.append(type)
movie_infos.append({"name": name, "type": type})
comments = movie.select('.hd a')[0]['href'] + 'comments' # 获取评论链接
movie_comments.append(comments)
j=json.dumps(movie_infos,ensure_ascii=False)#json.dumps 序列化时默认使用的ascii编码,想输出真正的中文需要指定ensure_ascii=False:
f.write(str(j))
def setcomment(file):
n = random.randint(0, 249)
url2 = movie_comments[n] # 随机抽取一条电影评论的链接
r = requests.get(url2, headers=headers) # 向豆瓣电影网页发送请求
soup = BeautifulSoup(r.text, 'html.parser') # 利用BeautifulSoup库解析响应页面
with open(file, 'w+', encoding='utf-8') as f2:
for comment in soup.select('.comment-item'): # 因为每页只有20条评论所以不需要读取下一页
s = comment.select('.comment p')[0].tt.strip()
f2.write(s + '\n')
if __name__=='__main__':
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36"}
file='movie.json'
getmovieinfo(url,headers,file)
setcomment('comments.txt')
#Segment.py
import jieba.posseg as psg
import thulac
def jsegall(str):
#带词性标注,对句子进行分词,不排除停词等
seg = psg.cut(str.strip())
s=''
for x in seg:
s+=("{}/{} ".format(x.word, x.flag))
return s
def tsegall(str):
thu = thulac.thulac(deli='/')#deli 默认为‘_’, 设置词与词性之间的分隔符
res = thu.cut(str, text=True)
return res
if __name__=='__main__':
while True:
a=input("请输入要处理的文本:")
b=int(input("请选择分词工具(1:JIEBA,2:THULAC):"))
if b==1:
print("结巴分词:[{}]".format(jsegall(a)))
if b==2:
print("THULAC分词:[{}]".format(tsegall(a)))
q=input("是否继续处理其他句子?y/n")
if q=='n':
break
#SegText.py
import jieba.posseg as psg
import thulac
def jsegall(sen):
#带词性标注,对句子进行分词,不排除停词等
with open("comments_out_jieba.txt",'w+',encoding='utf-8')as f:
seg = psg.cut(sen.strip())
s=''
for x in seg:
s+=("{}/{} ".format(x.word, x.flag))
f.write('结巴分词\n[{}]'.format(s))
print("生成文件已存到 ./comments_out_jieba.txt")
def tsegall(str):
with open("comments_out_thulac.txt",'w+',encoding='utf-8') as f:
thu = thulac.thulac(deli='/')#deli 默认为‘_’, 设置词与词性之间的分隔符
res = thu.cut(str, text=True)
f.write('THULAC分词\n[{}]'.format(res))
print("生成文件已存到 ./comments_out_thulac.txt")
if __name__=='__main__':
while True:
file=input("请输入要处理的文本路径:")
with open(file,'r',encoding='utf-8')as f:
s=f.read()
b=int(input("请选择分词工具(1:JIEBA,2:THULAC):"))
if b==1:
jsegall(s)
if b==2:
# print("THULAC分词:[{}]".format(thulac_use(s)))
tsegall(s)
q=input("是否继续除理其他文件?y/n")
if q=='n':
break
#WordCount.py
import jieba
import thulac
import jieba.analyse
import jieba.posseg
def jsegall(s):
#带词性标注,对句子进行分词,不排除停词等
seg = jieba.lcut(s.strip(),cut_all=False)#只分词不加词性标记
d=dict()
for i in seg:
y={i:seg.count(i)}
d.update(y)
return d
def tsegall(s):
thu = thulac.thulac(seg_only=True) #只进行分词,不进行词性标注
res = thu.cut(s, text=True)
l=res.split(' ')
d = dict()
for i in l:
y = {i: l.count(i)}
d.update(y)
return d
if __name__=='__main__':
while True:
a=input("请输入要处理的文本:")
b=int(input("请选择分词工具(1:JIEBA,2:THULAC):"))
if b==1:
print("结巴分词:",jsegall(a))
if b==2:
print("THULAC分词:",tsegall(a))
q=input("是否继续处理其他句子?y/n")
if q=='n':
break
#Word_Cloud.py
import matplotlib.pyplot as plt
import jieba
from wordcloud import WordCloud
s = open('comments.txt','r',encoding='utf-8').read()
set1=set(open('stopwords.txt','r',encoding='utf-8').read())#停用词
seg = jieba.cut(s)
res = " ".join(seg)#必须给个符号分隔开分词结果来形成字符串,否则不能绘制词云
wc = WordCloud(
# 设置字体,不指定就会出现乱码
font_path="C:\Windows\Fonts\STHUPO.TTF",
# 设置背景色
background_color='black',
# 设置背景宽
width=500,
# 设置背景高
height=350,
# 最大字体
max_font_size=150,
# 最小字体
min_font_size=10,
stopwords=set1,#停用词
# stopwords=set(),
mode='RGBA'
# colormap='pink'
)
wc.generate(res)#产生词云
#保存图片
wc.to_file(r"comments.png") # 按照设置的像素宽高度保存绘制好的词云图,比下面程序显示更清晰
# #指定所绘图名称
plt.figure('comments')
#以图片的形式显示词云
plt.imshow(wc)
#关闭图像坐标系
plt.axis('off')
plt.show()
运行结果:(每个人可能不同,因为电影选取是随机的)
moive.json:
comments.txt:
Segment.py运行结果:
SegText.py运行结果:
JIEBA分词:
THULAC分词:
WordCount.py运行结果:
Word_Cloud.py运行结果: