likes
comments
collection
share

爬取洛克王国宠物及做成搜索可视化界面

作者站长头像
站长
· 阅读数 13

爬取洛克王国宠物及做成搜索可视化界面

需求:爬取洛克王国的宠物、链接、图片和详情页的评论,做成一个可视化窗口,实现搜索宠物名字就会出现宠物图片和对应宠物详情页的评论,保存这些评论到 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行。

最后,代码肯定也会有不足的地方,欢迎提出,共同学习。