基于PyQt制作小红书图片抓取工具
作者:街 三 仔
闲言碎语
最近写一个系统,被一个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窗口贴合,达到一个美化的效果。
然后重写mousePressEvent、mouseMoveEvent和mouseReleaseEvent事件,实现鼠标在窗口中按下可移动的功能,其中还会带动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
以上就是基于PyQt制作小红书图片抓取工具的详细内容,更多关于PyQt图片抓取的资料请关注脚本之家其它相关文章!