自制多肉查询工具

news2024/9/22 13:26:44

背景:

复习python qt、网页解析的常用操作

准备:

  1. 多肉信息网站
  2. 涉及python的第三方库:
    • lxml
    • PyQt5

实现效果:

在这里插入图片描述

功能:

  1. 随机读取:从本地加载已存储的多肉信息
  2. 数据更新:从多肉信息网站更新5条多肉数据
  3. 查询:根据多肉的名字,查询本地存储的多肉信息
  4. 展示内容:
    • 多肉名称
    • 多肉介绍
    • 多肉图片

实现过程:

  1. 多肉信息爬取:

    1. 首页爬取多肉科目信息
      在这里插入图片描述

    2. 不同科目的多肉信息
      在这里插入图片描述

    3. 不同属的多肉信息获取
      在这里插入图片描述

    4. 实现代码:

      # -*- coding:UTF-8 -*-
      
      """
       @ProjectName  : pyExamples
       @FileName     : crawler
       @Description  : 爬取多肉信息
       @Time         : 2023/8/21 下午2:28
       @Author       : Qredsun
       """
      import os
      import time
      import random
      import pickle
      import requests
      from lxml import etree
      from loguru import logger
      
      '''多肉数据爬虫'''
      class SucculentCrawler():
          DEFAULT_UPDATE_NUM = 5 # 每次更新的多肉信息数量
          def __init__(self, **kwargs):
              self.__url = 'https://www.drlmeng.com/'
              self.referer_list = ["http://www.google.com/", "http://www.bing.com/", "http://www.baidu.com/", "https://www.360.cn/"]
              self.ua_list = ['Mozilla/5.0 (Linux; Android 5.1.1; Z828 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.111 Mobile Safari/537.36',
                              'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36',
                              'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22',
                              'Mozilla/5.0 (iPad; CPU OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/47.0.2526.107 Mobile/12F69 Safari/600.1.4',
                              'Mozilla/5.0 (iPad; CPU OS 11_2_5 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) CriOS/64.0.3282.112 Mobile/15D60 Safari/604.1',
                              'Mozilla/5.0 (Linux; Android 7.1.1; SM-T350 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36',
                              'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36',
                              'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36',
                              'Mozilla/5.0 (Linux; Android 6.0.1; SM-G610F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36',
                              'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
                              'Mozilla/5.0 (Linux; Android 5.1.1; 5065N Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Mobile Safari/537.36',
                              'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36',
                              'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36']
              self.page_urls = self.__getAllPageUrls()
              self.savedir = 'resources/succulents'
              self.page_pointer = 0
      
          '''爬取下一页数据'''
          def next(self):
              data = self.__parse_drlmeng_subject()
              self.__saveItem(data)
              time.sleep(random.random())
              return False
      
          '''多肉科目'''
          def __parse_drlmeng_subject(self):
      
              drlmeng_title = ''
              drlmeng_category_desc = []
              drlmeng_img_url = ''
      
              # 获取链接
              page_url = self.page_urls[self.page_pointer]
              # 提取该页中多肉的图片+详情页链接
              res = requests.get(page_url, headers=self.__randomHeaders())
              html = etree.HTML(res.text)
      
      
              archive_head = html.xpath('//*[@id="archive-head"]')
              if not len(archive_head):
                  logger.debug('解析多肉所属科失败')
                  return drlmeng_title, drlmeng_img_url, drlmeng_category_desc
      
              archive_head = archive_head[0]
              drlmeng_subject = archive_head.xpath('.//h1')
              if len(drlmeng_subject):
                  drlmeng_subject = drlmeng_subject[0].text.strip()
                  logger.debug(f'科:{drlmeng_subject}')
                  drlmeng_category_desc.append(drlmeng_subject)
      
              drlmeng_type_description = archive_head.xpath('.//div/p')
              if len(drlmeng_type_description):
                  drlmeng_type_description = drlmeng_type_description[0].text.strip()
                  logger.debug(f'科介绍:{drlmeng_type_description}')
                  drlmeng_category_desc.append(drlmeng_type_description)
      
              drlmengs = html.xpath('//ul[@class="posts-ul"]/li')
              drlmengs = drlmengs if drlmengs else html.xpath('//li[@class="row-thumb"]')
              if len(drlmengs):
                  random_index = random.randint(0, len(drlmengs))
                  drlmeng_info = drlmengs[random_index].xpath('.//a[@class="post-thumbnail"]')
                  if len(drlmeng_info):
                      drlmeng_info = drlmeng_info[0]
                      drlmeng_title = drlmeng_info.attrib.get('title')
                      drlmeng_title = drlmeng_title.replace('/','_')
      
                      drlmeng_desc_url = drlmeng_info.attrib.get('href')
                      drlmeng_category_desc.append(self.__parse_drlmeng_category(drlmeng_desc_url))
      
                      drlmeng_img_urls = drlmeng_info.xpath('.//img')
                      if len(drlmeng_img_urls):
                          drlmeng_img_url = drlmeng_img_urls[0].attrib.get('lazydata-src')
      
              self.page_pointer += 1
              return drlmeng_title, drlmeng_img_url, drlmeng_category_desc
      
          '''多肉属'''
          def __parse_drlmeng_category(self, drlmeng_desc_url):
              content = ''
              # # 提取该页中多肉的图片+详情页链接
              res = requests.get(drlmeng_desc_url, headers=self.__randomHeaders())
              html = etree.HTML(res.text)
      
              entry = html.xpath('//div[@class="entry"]')
              if len(entry):
                  entry = entry[0]
                  line_content = entry.xpath('.//p/text()')
      
                  for line in line_content:
                       line = line.replace('\u3000', '')
                       line = line.strip()
                       content += line
                  logger.debug(f'解析多肉详细介绍:{content}')
              return content
          '''数据保存'''
          def __saveItem(self, data):
              if not os.path.exists(self.savedir):
                  os.mkdir(self.savedir)
              if not data[0]:
                  return
              savepath = os.path.join(self.savedir, data[0])
              if not os.path.exists(savepath):
                  os.mkdir(savepath)
              f = open(os.path.join(savepath, 'show.jpg'), 'wb')
              f.write(requests.get(data[1], headers=self.__randomHeaders()).content)
              f.close()
              f = open(os.path.join(savepath, 'info.pkl'), 'wb')
              pickle.dump(data, f)
              f.close()
      
          '''获得所有链接'''
          def __getAllPageUrls(self):
              res = requests.get(self.__url, headers=self.__randomHeaders())
              html = etree.HTML(res.text)
              # html = etree.parse('/home/redsun/Downloads/pycharm-2020.2/run/config/scratches/scratch.html', etree.HTMLParser())
      
              ul_list = html.xpath('//ul[@class="sub-menu"]')
              page_urls = []
              for ul in ul_list:
                  page_urls.extend(ul.xpath('.//a/@href'))
                  if page_urls.__len__() >= self.DEFAULT_UPDATE_NUM:
                      page_urls = page_urls[:self.DEFAULT_UPDATE_NUM]
                      break
              return page_urls
      
          '''随机请求头'''
          def __randomHeaders(self):
              return {'user-agent': random.choice(self.ua_list), 'referer': random.choice(self.referer_list)}
      
      
      if __name__ == '__main__':
          c = SucculentCrawler()
          c.next()
      
  2. 窗口交互:

    # -*- coding:UTF-8 -*-
    
    """
     @ProjectName  : pyExamples
     @FileName     : SucculentQuery
     @Description  : 多肉信息查询工具外壳
     @Time         : 2023/8/21 下午2:28
     @Author       : Qredsun
     """
    import io
    import os
    import sys
    import random
    import threading
    from PIL import Image
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    from PyQt5 import QtGui
    from crawler import *
    
    
    '''多肉数据'''
    class SucculentQuery(QWidget):
        def __init__(self, parent=None, **kwargs):
            super(SucculentQuery, self).__init__(parent)
            self.setWindowTitle('多肉数据查询-微信公众号:Qredsun')
            self.setWindowIcon(QIcon('resources/icon/icon.jpg'))
            # 定义组件
            self.label_name = QLabel('多肉名称: ')
            self.line_edit = QLineEdit()
            self.button_find = QPushButton()
            self.button_find.setText('查询')
            self.label_result = QLabel('查询结果:')
            self.show_label = QLabel()
            self.show_label.setFixedSize(300, 300)
            self.showLabelImage('resources/icon/icon.png')
            self.text_result = QTextEdit()
            self.button_random = QPushButton()
            self.button_random.setText('随机读取')
            self.button_update = QPushButton()
            self.button_update.setText('数据更新')
            self.tip_label = QLabel()
            self.tip_label.setText('数据状态: 未在更新数据, 数据更新进度: 0/0')
            # 排版
            self.grid = QGridLayout()
            self.grid.addWidget(self.label_name, 0, 0, 1, 1)
            self.grid.addWidget(self.line_edit, 0, 1, 1, 30)
            self.grid.addWidget(self.button_find, 0, 31, 1, 1)
            self.grid.addWidget(self.button_random, 0, 32, 1, 1)
            self.grid.addWidget(self.button_update, 0, 33, 1, 1)
            self.grid.addWidget(self.tip_label, 1, 0, 1, 31)
            self.grid.addWidget(self.label_result, 2, 0)
            self.grid.addWidget(self.text_result, 3, 0, 1, 34)
            self.grid.addWidget(self.show_label, 3, 34, 1, 1)
            self.setLayout(self.grid)
            self.resize(600, 400)
            # 事件绑定
            self.button_find.clicked.connect(self.find)
            self.button_random.clicked.connect(self.randomRead)
            self.button_update.clicked.connect(lambda _: threading.Thread(target=self.update).start())
    
        '''数据查询'''
        def find(self):
            datadir = os.path.join('resources/succulents/', self.line_edit.text())
            if os.path.exists(datadir):
                self.showLabelImage(os.path.join(datadir, 'show.jpg'))
                intro = pickle.load(open(os.path.join(datadir, 'info.pkl'), 'rb'))[-1]
                self.showIntroduction(intro)
    
        '''随机读取'''
        def randomRead(self):
            datadir = random.choice(os.listdir('resources/succulents/'))
            self.line_edit.setText(datadir)
            datadir = os.path.join('resources/succulents/', self.line_edit.text())
            if os.path.exists(datadir):
                self.showLabelImage(os.path.join(datadir, 'show.jpg'))
                intro = pickle.load(open(os.path.join(datadir, 'info.pkl'), 'rb'))[-1]
                self.showIntroduction(intro)
    
        '''数据更新'''
        def update(self):
            crawler_handle = SucculentCrawler()
            while True:
                self.tip_label.setText(
                    '数据状态: 正在在更新数据, 数据更新进度: %s/%s' % (crawler_handle.page_pointer + 1, len(crawler_handle.page_urls)))
                crawler_handle.next()
                if crawler_handle.page_pointer == len(crawler_handle.page_urls):
                    break
            self.tip_label.setText('数据状态: 未在更新数据, 数据更新进度: 0/0')
    
        '''在文本框里显示多肉介绍'''
        def showIntroduction(self, intro):
            self.text_result.setText('\n\n'.join(intro))
    
        '''在Label对象上显示图片'''
        def showLabelImage(self, imagepath):
            image = Image.open(imagepath).resize((300, 300), Image.ANTIALIAS)
            fp = io.BytesIO()
            image.save(fp, 'JPEG')
            qtimg = QtGui.QImage()
            qtimg.loadFromData(fp.getvalue(), 'JPEG')
            qtimg_pixmap = QtGui.QPixmap.fromImage(qtimg)
            self.show_label.setPixmap(qtimg_pixmap)
    
    
    '''run'''
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        query_demo = SucculentQuery()
        query_demo.show()
        sys.exit(app.exec_())
    
  3. 项目结构:
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2068786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT:Qt与ECharts

介绍ECharts ECharts是一款基于JavaScript的数据可视化图表库,由百度团队最初开发,并在2018年初捐赠给Apache基金会,成为ASF孵化级项目。随着项目的不断发展,ECharts在2021年1月26日正式毕业,成为Apache顶级项目 链接…

背包问题【算法 07】

背包问题 背包问题是经典的计算机科学问题之一,涉及到如何在有限资源的约束下,选择最优的物品组合,以最大化收益。这个问题在现实中有广泛的应用,例如资源分配、物流调度和投资组合优化等。本文将详细介绍背包问题的定义、解决方法…

pytorch深度学习基础 7(简单的的线性训练,SGD与Adam优化器)

接下来小编来讲一下一些优化器在线性问题中的简单使用使用,torch模块中有一个叫optim的子模块,我们可以在其中找到实现不同优化算法的类 SGD随机梯度下降 基本概念 定义:随机梯度下降(SGD)是一种梯度下降形式&#…

mysql中出现错误1138-Invalid use of NULL value

问题:1138-Invalid use of NULL value 解决: 问题是当前字段中,有null的值,简单来说就是,你表里有空值,不能设置不为空!!! 把空的值删掉重新设计就好了

第一次重大人工智能失败刚刚发生

这终于发生了。我们迎来了第一家真正意义上的 AI 公司惨败。 Inflection是一家由比尔盖茨、埃里克施密特、微软等人投资的公司,它成为第一家被冲进马桶的生成式人工智能相关公司。 他们最重要的产品是Pi,ChatGPT 的竞争对手,专注于成为友好且…

SpringAOP使用详解

AOP使用详解 首先创建maven项目 添加依赖在pom.xml里 创建三层结构和spring.xml文件,只要用到注解就得写扫描包在spring.xml里 上篇文章的知识点总结 对上篇文章excution详细解释 如果把前置通知修改成这个代表只有带有Logger注解的才会生效 合并注解的方法用&…

Windows权限维持实战

目录 介绍步骤 介绍 在攻击过程中中对于拿到的shell或钓上来的鱼,目前比较流行用CS做统一管理,但实战中CS官方没有集成一键权限维持的功能,为了将该机器作为一个持久化的据点,种植一个具备持久化的后门,从而随时可以连…

ffmpeg最新5.1.6版本源码安装

一、编译安装需要的开源编码格式: 首先在编译安装这些开源编码格式之前,我们要明白为啥需要他们: aacx264x265 为啥需要呢?如果你对ffmpeg稍微了解的话,ffmpeg本身是一个框架,自身默认并没有支持这三种编码格式&…

Vue3 后台管理系统项目 前端部分

这里写目录标题 1 创建Vue3项目1.1 相关链接1.2 Vue Router1.3 Element1.4 scss1.5 mitt1.6 axios1.7 echarts1.8 配置vite.config.js 2 CSS部分2.1 样式穿透2.2 :style :在样式中使用插值语法 3. ElementUI3.1 rules: 数据验证3.2 修改element.style中的…

《计算机网络-期末模拟卷》

一、分析题(每题 6 分,共 36 分) 1.请分析图 1-1 所展示的是哪种互联网接入技术,分析此接入技术的优势,并介绍你所了解的其他互联网接入技术。(至少写 3 个) 二、计算问答题(每题 5…

docker应用

打包传输 1.将镜像打包 #查看帮助文件 docker --help #找到save,可以将镜像保存为一个tar包 docker save --help #查看save使用方式 #查看现有的镜像 docker images # docker save --output centos.tar centos:latest ls ...centos.tar... 可以将tar发送给其他用户…

JS基础进阶3-DOM事件

DOM事件流 一、定义 DOM事件流指的是从页面接收事件的顺序。这个路径包括了事件的捕获阶段、目标阶段和冒泡阶段。 图片来源黑马pink老师PPT 二、事件流阶段 DOM事件流涉及三个主要阶段: 捕获阶段(Capturing Phase): 事件从…

QtChart1-基础入门

Qt Charts概述 Qt Charts模块是一组易于使用的图标组件,它基于Qt的Graphice View架构,其核心组件是QChartView和QChart。QChartView的父类是QGraphicsView,就是Graphics View架构中的视图组件,所以,QChartView是用于显…

Apollo9.0 PNC源码学习之Planning模块—— Lattice规划(六):横纵向运动轨迹评估

参考文章: (1)Apollo6.0代码Lattice算法详解——Part6:轨迹评估及碰撞检测对象构建 (2)自动驾驶规划理论与实践Lattice算法详解 0 前言 横纵向运动轨迹的评估,主要通过构建定点巡航和定点停车两个场景下,对纵向运动参考速度、加速度、加加速度的大小进行检验和过滤,然…

Vue3源码调试-第一篇

前言 相信大家在前端从业生涯中都会被问到过,有了解过Vue源码吗?我是没有的,所以今天就来读好吧,浅浅读一下,顺便记录一下。 那究竟怎么读,从哪里读,我就不啰嗦了,直接给大家一个链…

python dash框架 油气田可视化软件设计文档

V1.1:机器学习框架(神经网络) 时间范围优化 表格布局优化 添加前端设计元素布局 V1.0:基础布局和对应计算函数 要求 首先第一部分是通过神经网络预测天然气流量,其中输入开始时间和截止时间是为了显示这一段时间内的天然气流量预测结果 第二部分&…

小型空气净化器可以除猫毛吗?宠物空气净化器评测推荐

前段时间我有个病人,诊断出来肺结节,他第一反应就是说他家养着好几只猫,会不会是吸入宠物毛发导致的肺结节。有些结节确实跟宠物有关系,如果是对毛发过敏、或者是对排泄物过敏,养宠物就会增加患结节的概率。不过就算是…

推荐一款AI智能编程助手CodeGeeX

最近,使用了一款AI智能编程助手CodeGeeX,感觉还不错,推荐给大家。 官网地址:https://codegeex.cn/ 一、安装教程 IDEA中安装插件:https://codegeex.cn/downloadGuide#idea VSCode中安装插件:https://codege…

八股(5)——数据库

八股(5)——数据库 4.1 数据库基础什么是数据库, 数据库管理系统, 数据库系统, 数据库管理员?什么是元组, 码, 候选码, 主码, 外码, 主属性, 非主属性?主键和外键有什么区别?为什么不推荐使用外键与级联?什么是 ER 图&#xff1…

TD学习笔记————中级教程总结(中)

目录 四、生成艺术 问题: CHOP TO放置后直接报错 附着不上线 五、Python Lists 与 Python Dictionaries 问题: 使用for的格式要求 显示numRows错误 List中表格定义报错 六、Replicate 与 Instance 问题: 传递处理好的噪音后不变化 Renderpass区分线和字时不起作用…