1.爬取网页正本小说,并保存到txt文件中;
2.利用词频统计小说中人物出现次数;
3.对出现最多的20个人名进行词云展示。
以下回答参考GPT并且由Bony-整理:
好的,你可以使用Python的Requests库和BeautifulSoup库来编写一个简单的网络爬虫,并使用jieba库来进行中文分词和生成词云。以下是一个示例代码:
import requests
from bs4 import BeautifulSoup
import jieba
from wordcloud import WordCloud
import matplotlib.pyplot as plt
# 下载小说
novel_url = 'https://www.example.com/novel'
response = requests.get(novel_url)
html = response.text
# 解析小说网页
soup = BeautifulSoup(html, 'html.parser')
novel_text = soup.find('div', class_='novel-text').text
# 分词并统计人名出现的次数
jieba.setLogLevel(20)
names_count = {}
for word in jieba.cut(novel_text):
if len(word) > 1 and word != '\r\n': # 只处理长度大于1的词语
if word in names_count:
names_count[word] += 1
else:
names_count[word] = 1
# 生成词云图
wordcloud = WordCloud(width=800, height=600, font_path='msyh.ttc', max_words=20, background_color='white').generate_from_frequencies(names_count)
plt.figure(figsize=(10, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()
请注意,上述示例仅供参考,实际的爬取过程可能涉及更复杂的页面解析和反爬虫机制,因此需要谨慎处理。此外,如果您要爬取的网站有相关的服务协议或法律法规,请务必遵守相关规定。
获取网页数据还是用 requests.get()方法。res = requests.get(url,params=params,headers=headers)
这样获取到的结果是一个 HTTP 状态码。
还需要用.text
方法再来获取一下这个结果里的文本信息。
#获取网页数据
html = requests.get(url)
htmlCode = html.text
有的网站对于反爬虫力度比较大,请求的时候可以构造一个请求头加上,请求头(Request Headers)在最前面开发者模式中的 Network 里就可以找到。
今天爬取的这个页面很简单,就直接 GET 请求 url 即可,可以啥都不带。
(我承认这段话是从我上篇文章里直接复制来的……)
接下来开始解析网页。
BeautifulSoup4 是将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,之后就可以利用 soup 加标签名轻松地获取这些标签的内容了。
参考beautifulsoup菜鸟教程
BeautifulSoup(markup,'html.parser')
#解析网页
soup = BeautifulSoup(htmlCode,'html.parser')
因为之前确定的实现思路是通过目录来获得小说所有章节的链接地址,然后分别对每一章内容进行爬取,所以接下来先要获得章节的目录。
前面分析过 在目录页面中,所有的目录链接都放在 < div class="book_list">
中的<a>
标签里,那么这里就可以用 soup.find('div', class_="book_list").find_all('a')
来获得所有符合条件的 <a>
标签了。
然后再看 <a>
标签的结构:
我们最终需要拿到的是 a 标签中的 href 属性值,获得href属性值的方法是a['href']
(这个小说的目录都是“第一节”、“第二节”这样,没什么用,就不用取出来了,如果是带有章节名称的话,可以考虑用 .text方法来获得 a 标签里的文字内容。)
这部分的代码是这样的:
soup = getHtml(url)
#查找所有章节的链接
listBox = soup.find('div', class_="book_list").find_all('a')
#新建列表用来储存list的url
bookLists = []
for i in listBox:
listUrl = i['href']
#放进列表里
bookLists.append(listUrl)
根据前面分析页面的结果,正文部分,是放在各个章节对应的正文页面的 < div class="contentbox">
中的,直接用 soup.find('div', class_="contentbox")
就可以获得对应 div 中的所有内容,以第一章为例,打印出来看一下。
现在这个内容是包含了 html 代码部分的,所以还需要用 .text
来获取其中的内容,再打印看看~ 是不是干净多了~
但是发现每一章后面还有几句话有点不好看,比如: “本章有错误,我要提交上一章 返回目录 下一章”、“小提示:按 回车[Enter]键 返回书目,按 ←键 返回上一页, 按 →键 进入下一页。” 之类的……
回到网页里看一下:
原因是正文底部的控件和文字也都包含在了 < div class="contentbox">
中了,暂时想不到其它比较好的获取正文内容的方法了,就只能把正文取出来以后再把多余的文字删掉了。
之后再简单处理一下,用.strip()
方法去掉收尾空格以后这部分就完成啦~
soup = getHtml(url)
#获得需要的正文内容
content = soup.find('div', class_="contentbox").text
content = content.strip()
contentCut = content.replace("本章未完,点击[ 下一页 ]继续阅读-->>","").replace("本章有错误,我要提交上一章 返回目录 下一章","").replace("小提示:按 回车[Enter]键 返回书目,按 ←键 返回上一页, 按 →键 进入下一页。","")
需要注意的是这里 getNovelContent() 的入参必须是章节正文页面的链接哟~ 就是目录页面地址和各章节 href 属性值拼接后的地址。
保存下来之前我还想把标题拿到,这样保存的时候就可以直接用小说的标题作为文件名了。
(对于一篇小说似乎看起来没什么用,但是如果要爬取多本小说的话,这个方法还是很有用的~)
还是在目录页来看,这个标题是放在<div class="book_info">
中的<h1 >
标签里,所以直接用 soup.find('div',class_="book_info").find('h1').string
就可以拿出来了。
soup = getHtml(url)
title = soup.find('div',class_="book_info").find('h1').string
保存时需要注意两点:
① 拼接完整的章节链接地址后才能调用获取各章节正文的函数 getNovelContent()
#获取各章节目录,这里的url是目录页的url
bookLists = getList(url)
for listUrl in bookLists:
#拼接完整的章节链接地址
chapterUrl = url + listUrl
chapterContent = getNovelContent(chapterUrl)
② 读写文件的方法
爬取小说和爬取图片的方法不同,小说需要将爬取到的内容写入本地文件中。
Python 的文件读取有两个最基本的用法,其一 with open(…) as …
,其二 open()
配合close()
。这里我选择用第一种方法啦~
简单扩展一下:
File.open() 方法 用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数。
File.write() 方法 用于向文件中写入指定字符串。
File.close() 方法 用于关闭一个已打开的文件,关闭后的文件不能再进行读写操作。使用 close() 方法关闭文件是一个好的习惯哟~。
(想起了 “把大象装进冰箱,总共分几步?”哈哈哈)
说明一下open()函数:open(name[, mode[, buffering]])
参数说明:
r: 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
a: 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
因为爬取小说的时候是一章一章地写入文件的,所以打开文件的模式需要用 “a”——追加模式
这部分的代码如下↓,在打开文件的时候加上了解码方式’utf-8’。
#获得章节目录
bookLists = getList(url)
#获得小说标题
title = getTitle(url)
#num用于下载时计数
num = 1
#以追加模式打开文件
with open('%s.txt'%title, 'a' ,encoding='utf-8') as f:
for listUrl in bookLists:
#拼接完整的章节链接地址
chapterUrl = url + listUrl
#获得对应章节正文内容
chapterContent = getNovelContent(chapterUrl)
#写入章节正文
f.write(chapterContent)
print('***第{}章下载完成***'.format(num))
num += 1
#关闭文件
f.close()
引用chatGPT作答,以下是一个基本的Python网络爬虫示例,可以实现爬取网页正本小说,并将其保存到txt文件中。
import requests
from bs4 import BeautifulSoup
# 定义要爬取的网址
url = 'https://www.example.com/novel/'
# 发送请求获取网页内容
response = requests.get(url)
html = response.text
# 使用BeautifulSoup解析网页内容
soup = BeautifulSoup(html, 'html.parser')
# 找到小说正文的标签
novel_content = soup.find('div', class_='novel-content')
# 将小说正文保存到txt文件中
with open('novel.txt', 'w', encoding='utf-8') as f:
f.write(novel_content.text)
接下来,可以利用Python中的collections模块和wordcloud库来实现对小说中人物出现次数的统计和词云展示。
import collections
import jieba
from wordcloud import WordCloud
import matplotlib.pyplot as plt
# 读取保存在txt文件中的小说内容
with open('novel.txt', 'r', encoding='utf-8') as f:
novel = f.read()
# 使用jieba分词对小说内容进行分词处理
words = jieba.cut(novel)
# 使用collections模块中的Counter类统计每个词语的出现次数
word_counts = collections.Counter(words)
# 找到出现最多的20个人名
top_20 = word_counts.most_common(20)
# 打印出现最多的20个人名及其出现次数
for name, count in top_20:
print(name, count)
# 使用wordcloud库生成词云
wc = WordCloud(font_path='msyh.ttf', background_color='white')
wc.generate_from_frequencies(word_counts)
# 显示词云图像
plt.imshow(wc)
plt.axis('off')
plt.show()
需要注意的是,上述代码中的msyh.ttf是一个中文字体文件,需要提前下载并保存到代码所在的文件夹中。