PyQt制作【小红书图片抓取】神器

news2024/11/21 0:39:18

文章目录

  • 📢闲言碎语
  • 🐾窗口设计
  • 🐾功能设计
  • 📚资源领取

在这里插入图片描述

📢闲言碎语

最近写一个系统,被一个Bug折腾了两天,至今还未解决。由于解决Bug弄得我有点心力憔悴,于是想着写其他小项目玩玩(爬取小红书图片),放松放松,在构思这个小项目的时候想着弄得稍微复杂点,弄着弄着花了大概三个小时时间(屁股要坐烂了),以为要准备结束了,结果又遇到Bug……😵

前前后后解决大大小小的Bug又花了大概一个小时😊

在这里插入图片描述

好在最终将Bug解决了,项目也成功的启动咯~

在这里插入图片描述

具体实现,请往下看👇

🐾窗口设计

如下图所示,主窗口主要有窗口图标、自动的鼠标图标、“小红书图片抓取”标签、带有frame窗口的QLineEdit和两个QPushButton,虽然看起来简单,但其背后逻辑功能的实现也不是很难。

首先需要定义一个子类Frame,并通过继承QFrame类来进行一些窗口的基本设置,设置其窗口的样式和背景颜色。

class Frame(QFrame):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFrameStyle(QFrame.Box | QFrame.Plain)
        self.setLineWidth(3)	# 外线宽
        self.setMidLineWidth(3)		# 中线宽 
        self.setStyleSheet("QFrame {border: 3px solid #ff2442;}")   # 设置边框颜色

接着设计主窗口,设置窗口和鼠标的图标,再设置基本的控件,其中setFrameWidget方法主要是将控件放在Frame窗口中,并通过传入的参数,计算控件的大小和移动的位置,让控件与Frame窗口贴合,达到一个美化的效果。

然后重写mousePressEventmouseMoveEventmouseReleaseEvent事件,实现鼠标在窗口中按下可移动的功能,其中还会带动processWindow(显示过程信息的窗口)的移动。

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        # 设置窗口
        self.setWindowTitle('小红书图片抓取')
        self.resize(400, 250)
        self.setWindowIcon(QIcon('window.png'))
        self.setStyleSheet('background-color: white;')

        # 设置鼠标
        self.setCursor(QCursor(QPixmap('mouse.png').scaled(30, 30), 0, 0))

        # 设置frame窗口宽度
        self.frameWidth = 3

        self.mouseFlag = False

        self.setup_ui()

    # 设置组件
    def setup_ui(self):
        # 设置窗口大标题
        label_title = QLabel(self)
        label_title.setText('小红书图片抓取')
        label_title.setStyleSheet('color: #ff2442')
        label_title.move(50, 10)
        label_title.setFont(QFont('华文行楷', 25))
        label_title.adjustSize()

        # 设置文本框接收
        self.lineEdit_filepath = self.setFrameWidget(QLineEdit, (130, 30), (70, 80))
        # 设置选择文件按钮
        self.button_selectFile = self.setFrameWidget(QPushButton, (100, 30), (220, 80))
        self.button_selectFile.setText("选择文件")
        self.button_selectFile.setFont(QFont('华文行楷', 13))
        self.button_selectFile.clicked.connect(lambda: self.selectFile(self.lineEdit_filepath))

        # 设置开始启动按钮
        self.button_start = self.setFrameWidget(QPushButton, (200, 70), (90, 150))
        self.button_start.setText('开始启动')
        self.button_start.setFont(QFont('华文行楷', 20))
        self.button_start.clicked.connect(self.start)
	
	    # 选择文件
    def selectFile(self, lineEdit):
        # 弹出对话框选择文件夹
        file_dialog = QFileDialog()
        file_dialog.setFileMode(QFileDialog.AnyFile)
        file_dialog.exec_()

        selected_files = file_dialog.selectedFiles()
        if selected_files:
            lineEdit.setText(selected_files[0])

    # 开始启动
    def start(self):
        self.setProcessWindow()
        # 实例化功能类
        appFunction = AppFunction(self.textEdit_process)
        # 获取小红书链接
        LinkUrls = appFunction.getLinkUrls(self.lineEdit_filepath.text())

        for linkurl in LinkUrls:
            t = threading.Thread(target=appFunction.run, args=(linkurl,))
            t.setDaemon(True)
            t.start()
            
    # 设置frame组件
    def setFrameWidget(self, widget, widget_size, widget_move, frameToplevel=None):
        if frameToplevel != None:
            frame = Frame(frameToplevel)
        else:
            frame = Frame(self)

        widget = widget(frame)
        frame.move(widget_move[0], widget_move[1])
        frame.resize(widget_size[0], widget_size[1])
        widget.move(self.frameWidth, self.frameWidth)
        widget.resize(widget_size[0] - self.frameWidth*2, widget_size[1] - self.frameWidth*2)

        if widget.inherits("QPushButton"):
            widget.setStyleSheet("background-color: #ff2442; color: white;")
        elif widget.inherits("QLineEdit") or widget.inherits("QTextEdit"):
            widget.setStyleSheet('border: none; font-weight: bold;')   # 设置为无边框

        return widget

    # 新窗口的设置
    def setProcessWindow(self):
        self.processWindow = ProcessWindow()
        self.processWindow.setGeometry(self.x()+500, self.y(), 250, 290)

        # 设置记录过程的textEdit
        self.textEdit_process = QTextEdit(self.processWindow)
        self.textEdit_process.resize(250, 290)
        self.textEdit_process.setStyleSheet('border: none; color: white;')    # 设置为无边框
        self.textEdit_process.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)     # 隐藏垂直滚动条
        self.processWindow.show()

    # 窗口移动
    def mousePressEvent(self, evt):
        if evt.button() == Qt.LeftButton:
            self.mouseFlag = True
            self.mouse_x, self.mouse_y = evt.globalPos().x(), evt.globalPos().y()
            self.origin_x, self.origin_y = self.x(), self.y()


    def mouseMoveEvent(self, evt):
        if self.mouseFlag == True:
            move_x = self.origin_x + (evt.globalPos().x() - self.mouse_x)
            move_y = self.origin_y + (evt.globalPos().y() - self.mouse_y)
            self.move(move_x, move_y)
            try:
                self.processWindow.move(move_x+500, move_y)     # 过程信息展示窗口移动
            except:
                pass

    def mouseReleaseEvent(self, evt):
        self.mouseFlag = False

    # 窗口关闭
    def closeEvent(self, evt):
        try:
            self.processWindow.close()
        except:
            pass

在设计显示过程信息的窗口时将窗口设置为半透明、背景颜色为黑色,并在其中添加QTextEdit输入框并设置其无边框和垂直滚动条为不可见,最终在整个程序执行时,会将不同过程不同颜色字体的信息放到输入框中显示,达到一个电影中常见的黑客操作信息时的炫酷效果。

    # 新窗口的设置
    def setProcessWindow(self):
        self.processWindow = ProcessWindow()
        self.processWindow.setGeometry(self.x()+500, self.y(), 250, 290)

        # 设置记录过程的textEdit
        self.textEdit_process = QTextEdit(self.processWindow)
        self.textEdit_process.resize(250, 290)
        self.textEdit_process.setStyleSheet('border: none; color: white;')    # 设置为无边框
        self.textEdit_process.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)     # 隐藏垂直滚动条
        self.processWindow.show()
        
# ====================================== 新窗口-过程信息展示区 ======================================
class ProcessWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowFlag(Qt.FramelessWindowHint)  # 将窗口设置为无边框无标题
        self.setWindowOpacity(0.5)  # 将窗口设置为半透明
        self.setStyleSheet('background-color: black;')

🐾功能设计

功能设计主要实现读取excel中的链接、访问链接、在显示过程信息的窗口的输入框中插入信息、获取图片URL、爬取并下载图片。

# ====================================== 爬取图片能执行 ======================================
class AppFunction:
    def __init__(self, textEdit):
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
        }

        self.pattern = 'url\("(.*)"\);'

        self.nowPath = os.getcwd()

        self.textEdit = textEdit

        self.cursor = self.textEdit.textCursor()    # 获取光标位置
        # 红色
        self.red = QColor(Qt.yellow)
        # 绿色
        self.green = QColor(Qt.green)
        # 驱动路径
        driver_path = 'D:\chromedriver-win32\chromedriver.exe'
        # 固定搭配直接用就行了
        self.service = Service(executable_path=driver_path)
        # 无头模式
        self.option = webdriver.ChromeOptions()
        self.option.add_experimental_option('excludeSwitches', ['enable-automation'])
        self.option.add_argument('--disable-blink-features=AutomationControlled')
        # self.option.add_argument('--headless')

    # 执行方法
    def run(self, url):
        self.getPhotoUrl(url)

    # 插入文本
    def insertText(self, text, color):
        format = QTextCharFormat()
        format.setForeground(color)
        self.cursor.insertText(text, format)    # 在QTextEdit中插入文字
        self.textEdit.ensureCursorVisible()     # 在插入的时候随着光标向下滚动,即达到文字自动滚动效果

    # 获取图片URL
    def getPhotoUrl(self, url):
        url = url
        driver = webdriver.Chrome(service=self.service, options=self.option)
        self.insertText('\n' + url + ' -- 开始抓取图片URL', self.red)
        driver.get(url)

        # 等待图片URL出现
        WebDriverWait(driver, 1000).until(
            EC.presence_of_element_located((By.XPATH, '//div[@class="swiper-wrapper"]/div'))
        )
        # 获取图片URL
        temp_PhotoUrls = [i.get_attribute('style') for i in driver.find_elements(By.XPATH, '//div[@class="swiper-wrapper"]/div')]
        # 获取小红书标题
        title = driver.find_element(By.XPATH, '//div[@id="detail-title"]').text

        # 正则方法清洗图片url
        PhotoUrls = list(set([re.findall(self.pattern, i)[0] for i in temp_PhotoUrls]))

        # 关闭浏览器
        driver.close()
        self.insertText('\n' + url + ' -- 图片URL抓取完成', self.green)

        self.getPhoto(PhotoUrls, title)

    # 获取图片
    def getPhoto(self, PhotoUrls, title):
        path = os.path.join(self.nowPath, title)
        if not os.path.exists(path):  # 创建文件夹
            os.makedirs(path)

        for i in range(len(PhotoUrls)):
            self.insertText('\n' + PhotoUrls[i] + ' -- 开始抓取图片', self.red)

            res = requests.get(PhotoUrls[i], headers=self.headers)
            with open(f'./{title}/{i}.webp', 'wb') as f:
                f.write(res.content)
                self.insertText('\n' + f'{self.nowPath}\\{title}\\{i}.png' + ' -- 下载完成', self.green)
        self.insertText(f'\n{title}图片下载完成!\n'.center(71, '='), self.green)

    # 读取文件,获取网页链接
    def getLinkUrls(self, path):
        f = openpyxl.load_workbook(path)
        sheet = f['Sheet1']
        LinkUrls = [i.value for i in sheet['A']]
        return LinkUrls

📚资源领取

关注微信公众号👉【Python小作坊】,回复💬“小红书图片爬取”,即可免费领取(含源代码)~
在这里插入图片描述

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

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

相关文章

STM32F407的看门狗

文章目录 看门狗时钟两种看门狗IWDG结构图作用 寄存器IWDG_KR键值寄存器IWDG_PR预分频寄存器2-0 PR预分频器系数 IWDG_RLR重装载寄存器IWDG_SR状态寄存器1RVU 重载值更新0 PVU 预分频值更新注意 写保护超时时间使用步骤取消寄存器 写保护设置预分频系数和重装载值看门狗溢出时间…

2023年第十六届山东省职业院校技能大赛中职组“网络安全”赛项规程

第十六届山东省职业院校技能大赛 中职组“网络安全”赛项规程 一、赛项名称 赛项名称:网络安全 英文名称:Cyber Security 赛项组别:中职组 专业大类:电子与信息大类 二、竞赛目的 网络空间已经成为陆、海、空、天之后的第…

Openlayers:自定义Controls

Openlayers是一款优秀的二维开源地图框架,支持矢量/栅格图层,支持移动端,并且易于自定义和拓展。下面来讲述一下自定义Control的基本思路。 openlayers-features 问题描述 最近在做个人项目时,遇到了一个小问题,就是在地图中心添加一个十字针形状的符号,用来表示地图中心…

第25章_索引优化与查询优化

文章目录 1. 数据准备2.索引失效案例2.1全值匹配2.2最佳左前缀法则2.3主键插入顺序2.4 计算、函数导致索引失效2.5 类型转换导致索引失效2.6 范围条件右边的列索引失效2.7 不等于(! 或者<>)索引失效2.8 is null可以使用索引&#xff0c;is not null无法使用索引2.9 like以…

【数据结构初阶】顺序表SeqList

描述 顺序表我们可以把它想象成在一个表格里面填数据&#xff0c;并对数据做调整&#xff1b; 那我们的第一个问题是&#xff1a;怎么样在创建出足够的空间呢&#xff1f; 我们可以去堆上申请&#xff0c;用一个指针指向一块空间&#xff0c;如果申请的空间不够&#xff0c;我…

Spring基础学习——web

Spring基础学习——web 一、Spring整合Web环境1.1 JavaWeb三大组件作用及其特点1.2 Spring整合Web环境的思路及实现1.3 Spring开发Web环境组件spring-web1.4 web层MVC框架思想与设计思路 一、Spring整合Web环境 1.1 JavaWeb三大组件作用及其特点 在Java语言当中&#xff0c;w…

2023亚太杯数学建模A题思路

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

【Java】Java8 Function 和 Consumer 接口的使用场景

文章目录 前言1. Function 示例2. Function 介绍3. Consumer 示例4. Consumer 介绍5. Function 和 Consumer 接口的使用场景后记 前言 在 《精通Java8》一书中有讲过 Java8的函数式接口可以简化设计模式的实施&#xff0c;这里记录一下Function 和 Consumer 的使用场景。 1. …

docker主备节点数据同步

主备节点挂载 在生产环境中&#xff0c;赋予一个docker操作系统的权限是一件不安全的事&#xff0c;在不具有系统操作权限的情况下&#xff0c;主备机无法通过nfs进行挂载。此时&#xff0c;可借助数据卷进行挂载 创建两个数据卷 docker volume create vol1 docker volume cr…

Java常用设计模式(23种)

文章目录 介绍 设计模式的六大原则 一、创建型模式 1、单例模式&#xff08;Singleton Pattern&#xff09; 1&#xff09;饿汉式 2&#xff09;懒汉式&#xff0c;双检锁 3&#xff09;静态内部类 4&#xff09;枚举 2、原型模式&#xff08;Prototype Pattern&#xff09…

(免费领源码)java#ssm#mysql在线学习平台85204-计算机毕业设计项目选题推荐

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;在线学习平台当然也不能排除在外。在线学习平台是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#x…

线索二叉树(存储结构,线索化,寻找前驱/后继)

目录 1.线索二叉树1.中序线索二叉树2.后序线索二叉树3.先序线索二叉树 2.线索二叉树的存储结构3.二叉树的线索化1.中序线索化2.先序线索化3.后序线索化 4.寻找前驱/后继1.中序线索二叉树找后继2.中序线索二叉树找中序前驱3.先序线索二叉树找先序后继4.先序线索二叉树找先序前驱…

会员题-力扣408-有效单词缩写

有效单词缩写 字符串可以用 缩写 进行表示&#xff0c;缩写 的方法是将任意数量的 不相邻 的子字符串替换为相应子串的长度。例如&#xff0c;字符串 “substitution” 可以缩写为&#xff08;不止这几种方法&#xff09;&#xff1a; “s10n” (“s ubstitutio n”) “sub4…

配置交换机将Log发送到日志服务器

文章目录 一、配置说明二、配置步骤推荐阅读 一、配置说明 配置将实现如下&#xff1a; 配置交换机将Log发送到日志服务器。 将信息等级高于等于 debug 的日志信息将会发送到日志服务器上。 允许输出日志信息的模块为default所有应用模块日志信息。 SW1为我们日志源交换机…

Clickhouse学习笔记(12)—— 物化视图

ClickHouse 的物化视图是一种查询结果的持久化&#xff0c;与普通视图对比&#xff0c;其不仅保存了查询的逻辑&#xff0c;还保存了查询结果&#xff1b; 物化视图与普通视图的区别 普通视图不保存数据&#xff0c;保存的仅仅是查询语句&#xff0c;查询的时候还是从原表读取…

画面精美传奇手游幽冥传奇【幽冥灭龙传奇】win服务端+双端+GM授权后台+详细教程

搭建资源下载地址&#xff1a;画面精美传奇手游幽冥传奇幽冥灭龙传奇win服务端双端GM授权后台详细教程-海盗空间

JuCheap开发的微信小程序商城(NetCore商城)

一、目的 最近工作需要&#xff0c;在学习微信小程序的开发&#xff0c;用周末空闲时间开发了一个微信小程序商城。 二、功能 2.1 管理后台 管理后台是基于JuCheap开发的&#xff0c;使用Net6Vue3ElementPlus开发&#xff0c;具体功能包含如下&#xff1a; 2.1.1 店铺模块…

lc228. 汇总区间

暴力解法&#xff1a;遍历数组&#xff0c;判断数组是否连续递增。将连续递增的数据的首尾的数据分别存储在map集合的key和value之中&#xff0c;输出时判断首尾值是否相同采用两种方式输出 复杂度分析 时间复杂度&#xff1a;O(n)&#xff0c;其中 n 为数组的长度。空间复杂…

环形链表解析(c语言)c语言版本!自我解析(看了必会)

目录 1.判断一个表是否是环形链表&#xff01; 代码如下 解析如下 2.快指针的步数和慢指针的步数有什么影响&#xff08;无图解析&#xff09; 3.怎么找到环形链表的入环点 代码如下 解析如下 1.判断一个表是否是环形链表&#xff01; 代码如下 bool hasCycle(struct L…

ZDH-智能营销-执行流程解析

目录 项目源码 预览地址 安装包下载地址 通过2个方向解读ZDH流程图 图执行方向 数据流转方向 项目源码 zdh_web: GitHub - zhaoyachao/zdh_web: 大数据采集,抽取平台 zdh_magic_mirror: https://github.com/zhaoyachao/zdh_magic_mirror 预览地址 后台管理-登陆 用户…