爬取洛克王国宠物及做成搜索可视化界面
爬取洛克王国宠物及做成搜索可视化界面
需求:爬取洛克王国的宠物、链接、图片和详情页的评论,做成一个可视化窗口,实现搜索宠物名字就会出现宠物图片和对应宠物详情页的评论,保存这些评论到 txt 文本中及对评论进行文本分析,做成一个关键词的词云图并保存。
网址:洛克王国宠物大全
1、分析网页及对一级网页发起请求
查看网页可以发现所有的宠物都在id为cwdz_list的ul列表下li里,因此可以用xpath语法解析出所有的宠物名和详情链接和图片,图片的链接是少了前缀的,尝试加上https:前缀,刚好是访问了宠物对应的图片。
2、分析宠物详情页及爬取评论
2.1获取评论内容网址
查看二级页面加载的第一个文件,发现并没有评论的信息,简单对二级页面发起请求并不能得到评论,查看加载的所有document文件可以发现评论内容是在第二个文件里
查看这个文件的标头,对这个请求网址和我们在一级页面爬到的宠物详情页网址做分析
网页网址
https://news.4399.com/luoke/luokechongwu/guangxi/642942.html
评论文档网址
https://comment.5054399.com/luoke/2942/642942_1.html?dm=news.4399.com
可以发现爬到的网址后的数字编号与评论的网址上的数字编号有关联,后四位为第一组数字,第二组数字刚好就是所有数字,多点开几个详情页可以发现这样的规律仍然成立,因此可以用正则匹配出数字编号然后生成对应的网址,对网址发起请求获得评论内容。
2.2爬取评论
对上述文档分析,评论的内容都是在p标签里面的,尝试向评论网址发起请求并使用BeautifulSoup类获取所有的p标签内容,得到了下面的结果
直接用if判断去掉为空的元素,并去掉最后一句不属于评论的内容,这样得到的内容就全是评论了
3、可视化界面及搜索功能
3.1可视化界面的制作
界面控件主要包括执行的按钮、供用户查找宠物名的输入框、输出评论内容的文本框等,其中的代码都是比较固定的
root = tkinter.Tk()
root.title('洛克王国宠物搜索')
root.geometry('800x600')
root.resizable(False, False) # 使窗口大小不能被改变
# 提示词
find_text = tkinter.Label(root, text='请输入宠物名:', font=('Arial', 12), width=30, height=2)
find_text.pack()
# 搜索输入框
entry = tkinter.Entry(root, show=None, font=('Arial', 14))
entry.pack(after=find_text)
# 搜索按钮,search是点击按钮就会运行的函数的函数名
find = tkinter.Button(root, text='搜索', font=('Arial', 12), width=10, height=1, command=search)
find.pack()
# 图片存放的位置
img_label = tkinter.Label(root, width=200, height=150)
img_label.pack()
# 输出文本框
output = tkinter.Text(root)
# 滑条
scroll = tkinter.Scrollbar()
scroll.pack(side=tkinter.RIGHT, fill=tkinter.Y)
center(root)
root.mainloop()
3.2搜索功能的实现
搜索功能的流程大概就是根据用户输入的宠物名使对应的宠物图片出现,同时爬取对应网页的评论并把评论输出到文本框中,还对爬到的评论进行权重分词,获取其中的关键词,把关键词用词云图的方式呈现出来,并保存得到的评论和词云图。每一次的搜索都是重复这些功能,这样就完成了整个的项目。
4、最终效果
4.1爬取的图片
4.2保存的宠物名及链接
4.3保存的词云图及评论
4.4搜索例子
5、代码汇总
# -*- coding:utf-8 -*-
# 导入库
from bs4 import BeautifulSoup
from lxml import etree
import pandas as pd
import jieba
import requests
import tkinter
import numpy as np
from PIL import Image, ImageTk
import os
import re
import jieba.analyse
from wordcloud import WordCloud
def get_data(url, headers):
"""
对网页发起请求
:param url: 请求网址
:param headers: 请求头
:return: 返回得到的网页数据
"""
response = requests.get(url, headers)
response.encoding = response.apparent_encoding # 使用原网页的字符编码,避免出现乱码
return response.text
def save_png(url, name):
"""
对宠物图片链接发起请求,并保存图片
:param url: 宠物图片链接
:param name: 宠物名,作为图片的命名
:return:null
"""
if not os.path.exists('宠物png'):
os.makedirs('宠物png') # 创建保存图片的文件夹
else:
try:
png_data = requests.get(url, headers).content
with open('宠物png/{}.jpg'.format(name), 'wb') as f:
f.write(png_data)
except:
print('爬取图片错误,错误位置:', name)
def analyse(one_data):
"""
解析出宠物的名字,链接及图片链接
:param one_data:一级网页请求返回的数据
:return:返回一个有名字、链接、图片链接的二维列表
"""
x_data = etree.HTML(one_data)
names = x_data.xpath('//ul[@id="cwdz_list"]/li/@name')
hrefs = x_data.xpath('//ul[@id="cwdz_list"]/li/a/@href')
pngs = x_data.xpath('//ul[@id="cwdz_list"]/li/a/img/@lz_src')
val = [[], [], []]
print('正在爬取')
# 保存解析的信息
for name, href, png in zip(names, hrefs, pngs):
val[0].append(name)
val[1].append('https://news.4399.com' + href)
val[2].append('https:' + png)
save_png('https:' + png, name)
df = pd.DataFrame(np.array(val).T) # 转为DataFrame类型便于保存
df.to_excel('宠物链接.xls', sheet_name='宠物链接', index=False)
print('爬取完成')
return val
def get_num(href):
"""
对宠物链接进行解析,得到对应的数字编号
:param href: 宠物链接
:return: 宠物编号
"""
num = re.match('.*?(\d+)\.html$', href)
return num.group(1)
def get_comment(name):
"""
根据搜索的宠物名获取评论内容并画出词云图
:param name: 用户输入的宠物名
:return: 返回评论列表或错误列表
"""
if name in information[0]:
index = information[0].index(name)
num = get_num(information[1][index])
try:
# 向评论页网址发起请求
two_data = get_data(f'https://comment.5054399.com/luoke/{num[-4:]}/{num}_1.html?dm=news.4399.com', headers)
bs_data = BeautifulSoup(two_data, 'lxml')
p = bs_data.find_all('p')[:-1]
comment = []
for i in p:
if i.string is not None:
comment.append(i.string)
# 将评论写入txt文本中
with open('{}评论.txt'.format(name), 'a', encoding='utf-8') as f:
f.write(i.string + '\n')
"""
对获取到的评论进行权重分析并绘制关键词词云图
"""
comment_text = ' '.join(comment)
tag = jieba.analyse.extract_tags(sentence=comment_text, topK=20) # 分析文本得到关键词
cloud = WordCloud(font_path='hpsimplifiedhans-light.ttf').generate(' '.join(tag))
cloud.to_file('{}词云图.jpg'.format(name))
"""
生成一个显示图片的窗口,用来显示词云图
"""
window = tkinter.Toplevel(root)
window.title('{}词云图.jpg'.format(name))
photo = ImageTk.PhotoImage(Image.open('{}词云图.jpg'.format(name)))
cloud_label = tkinter.Label(window, image=photo)
cloud_label.image = photo
cloud_label.pack()
return comment # 返回评论文本,用于在文本输出框输出
except:
return [f'评论网址错误,错误网址为https://comment.5054399.com/luoke/{num[-4:]}/{num}_1.html?dm=news.4399.com']
else:
return ['没有这个宠物']
def center(root):
"""
使主窗口生成在屏幕中间
:param root: 窗口
:return: null
"""
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = int((ws / 2) - (800 / 2))
y = int((hs / 2) - (600 / 2))
root.geometry('{}x{}+{}+{}'.format(800, 600, x, y))
def search():
"""
查找函数,点击按钮就执行这个函数,生成宠物的图片及写入评论到文本框中
:return: null
"""
comment_data = get_comment(entry.get())
# 使滑动条与文本框关联,确保文本框可以显示更多文本
scroll.config(command=output.yview)
output.config(yscrollcommand=scroll.set)
output.pack()
if comment_data != ['没有这个宠物']: # 找到宠物的情况
try: # 显示宠物图片
img = Image.open('宠物png/{}.jpg'.format(entry.get()))
img_tk = ImageTk.PhotoImage(img)
img_label.configure(image=img_tk)
img_label.image = img_tk
except:
# 没有图片用空白的图片显示,以便文本框正常出现
img = Image.open('无宠物.jpg'.format(entry.get()))
img_tk = ImageTk.PhotoImage(img)
img_label.configure(image=img_tk)
img_label.image = img_tk
comment_data += ['没有找到图片']
# 将评论一条条写入文本框中
for i in comment_data:
output.insert('insert', i)
output.insert('insert', '\n')
output.see("insert")
else:
# 没有图片用空白的图片显示,以便文本框正常出现
img = Image.open('无宠物.jpg'.format(entry.get()))
img_tk = ImageTk.PhotoImage(img)
img_label.configure(image=img_tk)
img_label.image = img_tk
output.insert('insert', comment_data[0])
output.insert('insert', '\n')
output.see("insert")
output.insert('insert', '\n' * 3) # 换行,与前面查询的评论区别开
output.see("insert")
if __name__ == '__main__':
"""
主函数,包括调用函数,生成主窗口及窗口元素
"""
url = "https://news.4399.com/luoke/luokechongwu/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.57'
}
data = get_data(url, headers)
information = analyse(data)
"""
生成主窗口
"""
root = tkinter.Tk()
root.title('洛克王国宠物搜索')
root.geometry('800x600')
root.resizable(False, False) # 使窗口大小不能被改变
# 提示词
find_text = tkinter.Label(root, text='请输入宠物名:', font=('Arial', 12), width=30, height=2)
find_text.pack()
# 搜索输入框
entry = tkinter.Entry(root, show=None, font=('Arial', 14))
entry.pack(after=find_text)
# 搜索按钮
find = tkinter.Button(root, text='搜索', font=('Arial', 12), width=10, height=1, command=search)
find.pack()
# 图片存放的位置
img_label = tkinter.Label(root, width=200, height=150)
img_label.pack()
# 输出文本框
output = tkinter.Text(root)
# 滑条
scroll = tkinter.Scrollbar()
scroll.pack(side=tkinter.RIGHT, fill=tkinter.Y)
center(root)
root.mainloop()
最后代码的运行除了要安装较多的库外,还要两个文件,一个是字体类型文件,可以在电脑的C盘找得到
把自己挑选的文件放在与代码相同文件夹内,并把我代码中的107行的文件名改成你要更改的文件名。另一个是一张全白的图片,如果搜不到宠物就可以替代原来图片的位置,这个图片我命名为无宠物.jpg,在代码中的位置为156行和168行。
最后,代码肯定也会有不足的地方,欢迎提出,共同学习。
转载自:https://juejin.cn/post/7240065163485954109