基于PyQt制作小紅書圖片抓取工具
閑言碎語(yǔ)
最近寫一個(gè)系統(tǒng),被一個(gè)Bug折騰了兩天,至今還未解決。由于解決Bug弄得我有點(diǎn)心力憔悴,于是想著寫其他小項(xiàng)目玩玩(爬取小紅書圖片),放松放松,在構(gòu)思這個(gè)小項(xiàng)目的時(shí)候想著弄得稍微復(fù)雜點(diǎn),弄著弄著花了大概三個(gè)小時(shí)時(shí)間(屁股要坐爛了),以為要準(zhǔn)備結(jié)束了,結(jié)果又遇到Bug……
前前后后解決大大小小的Bug又花了大概一個(gè)小時(shí)
好在最終將Bug解決了,項(xiàng)目也成功的啟動(dòng)咯~
具體實(shí)現(xiàn),請(qǐng)往下看
窗口設(shè)計(jì)
如下圖所示,主窗口主要有窗口圖標(biāo)、自動(dòng)的鼠標(biāo)圖標(biāo)、“小紅書圖片抓取”標(biāo)簽、帶有frame窗口的QLineEdit和兩個(gè)QPushButton,雖然看起來簡(jiǎn)單,但其背后邏輯功能的實(shí)現(xiàn)也不是很難。
首先需要定義一個(gè)子類Frame,并通過繼承QFrame類來進(jìn)行一些窗口的基本設(shè)置,設(shè)置其窗口的樣式和背景顏色。
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;}") # 設(shè)置邊框顏色
接著設(shè)計(jì)主窗口,設(shè)置窗口和鼠標(biāo)的圖標(biāo),再設(shè)置基本的控件,其中setFrameWidget方法主要是將控件放在Frame窗口中,并通過傳入的參數(shù),計(jì)算控件的大小和移動(dòng)的位置,讓控件與Frame窗口貼合,達(dá)到一個(gè)美化的效果。
然后重寫mousePressEvent、mouseMoveEvent和mouseReleaseEvent事件,實(shí)現(xiàn)鼠標(biāo)在窗口中按下可移動(dòng)的功能,其中還會(huì)帶動(dòng)processWindow(顯示過程信息的窗口)的移動(dòng)。
class MainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) # 設(shè)置窗口 self.setWindowTitle('小紅書圖片抓取') self.resize(400, 250) self.setWindowIcon(QIcon('window.png')) self.setStyleSheet('background-color: white;') # 設(shè)置鼠標(biāo) self.setCursor(QCursor(QPixmap('mouse.png').scaled(30, 30), 0, 0)) # 設(shè)置frame窗口寬度 self.frameWidth = 3 self.mouseFlag = False self.setup_ui() # 設(shè)置組件 def setup_ui(self): # 設(shè)置窗口大標(biāo)題 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() # 設(shè)置文本框接收 self.lineEdit_filepath = self.setFrameWidget(QLineEdit, (130, 30), (70, 80)) # 設(shè)置選擇文件按鈕 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)) # 設(shè)置開始啟動(dòng)按鈕 self.button_start = self.setFrameWidget(QPushButton, (200, 70), (90, 150)) self.button_start.setText('開始啟動(dòng)') self.button_start.setFont(QFont('華文行楷', 20)) self.button_start.clicked.connect(self.start) # 選擇文件 def selectFile(self, lineEdit): # 彈出對(duì)話框選擇文件夾 file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.AnyFile) file_dialog.exec_() selected_files = file_dialog.selectedFiles() if selected_files: lineEdit.setText(selected_files[0]) # 開始啟動(dòng) def start(self): self.setProcessWindow() # 實(shí)例化功能類 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() # 設(shè)置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;') # 設(shè)置為無邊框 return widget # 新窗口的設(shè)置 def setProcessWindow(self): self.processWindow = ProcessWindow() self.processWindow.setGeometry(self.x()+500, self.y(), 250, 290) # 設(shè)置記錄過程的textEdit self.textEdit_process = QTextEdit(self.processWindow) self.textEdit_process.resize(250, 290) self.textEdit_process.setStyleSheet('border: none; color: white;') # 設(shè)置為無邊框 self.textEdit_process.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 隱藏垂直滾動(dòng)條 self.processWindow.show() # 窗口移動(dòng) 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) # 過程信息展示窗口移動(dòng) except: pass def mouseReleaseEvent(self, evt): self.mouseFlag = False # 窗口關(guān)閉 def closeEvent(self, evt): try: self.processWindow.close() except: pass
在設(shè)計(jì)顯示過程信息的窗口時(shí)將窗口設(shè)置為半透明、背景顏色為黑色,并在其中添加QTextEdit輸入框并設(shè)置其無邊框和垂直滾動(dòng)條為不可見,最終在整個(gè)程序執(zhí)行時(shí),會(huì)將不同過程不同顏色字體的信息放到輸入框中顯示,達(dá)到一個(gè)電影中常見的黑客操作信息時(shí)的炫酷效果。
# 新窗口的設(shè)置 def setProcessWindow(self): self.processWindow = ProcessWindow() self.processWindow.setGeometry(self.x()+500, self.y(), 250, 290) # 設(shè)置記錄過程的textEdit self.textEdit_process = QTextEdit(self.processWindow) self.textEdit_process.resize(250, 290) self.textEdit_process.setStyleSheet('border: none; color: white;') # 設(shè)置為無邊框 self.textEdit_process.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 隱藏垂直滾動(dòng)條 self.processWindow.show() # ====================================== 新窗口-過程信息展示區(qū) ====================================== class ProcessWindow(QWidget): def __init__(self): super().__init__() self.setWindowFlag(Qt.FramelessWindowHint) # 將窗口設(shè)置為無邊框無標(biāo)題 self.setWindowOpacity(0.5) # 將窗口設(shè)置為半透明 self.setStyleSheet('background-color: black;')
功能設(shè)計(jì)
功能設(shè)計(jì)主要實(shí)現(xiàn)讀取excel中的鏈接、訪問鏈接、在顯示過程信息的窗口的輸入框中插入信息、獲取圖片URL、爬取并下載圖片。
# ====================================== 爬取圖片能執(zhí)行 ====================================== 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() # 獲取光標(biāo)位置 # 紅色 self.red = QColor(Qt.yellow) # 綠色 self.green = QColor(Qt.green) # 驅(qū)動(dòng)路徑 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') # 執(zhí)行方法 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() # 在插入的時(shí)候隨著光標(biāo)向下滾動(dòng),即達(dá)到文字自動(dòng)滾動(dòng)效果 # 獲取圖片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出現(xiàn) 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')] # 獲取小紅書標(biāo)題 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])) # 關(guān)閉瀏覽器 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): # 創(chuàng)建文件夾 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) # 讀取文件,獲取網(wǎng)頁(yè)鏈接 def getLinkUrls(self, path): f = openpyxl.load_workbook(path) sheet = f['Sheet1'] LinkUrls = [i.value for i in sheet['A']] return LinkUrls
以上就是基于PyQt制作小紅書圖片抓取工具的詳細(xì)內(nèi)容,更多關(guān)于PyQt圖片抓取的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python 注解方式實(shí)現(xiàn)緩存數(shù)據(jù)詳解
這篇文章主要介紹了Python 注解方式實(shí)現(xiàn)緩存數(shù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-10-10Python?"手繪風(fēng)格"數(shù)據(jù)可視化方法實(shí)例匯總
這篇文章主要給大家介紹了關(guān)于Python?"手繪風(fēng)格"數(shù)據(jù)可視化方法實(shí)現(xiàn)的相關(guān)資料,本文分別給大家?guī)砹薖ython-matplotlib手繪風(fēng)格圖表繪制、Python-cutecharts手繪風(fēng)格圖表繪制以及Python-py-roughviz手繪風(fēng)格圖表繪制,需要的朋友可以參考下2022-02-02Python實(shí)現(xiàn)數(shù)據(jù)透視表詳解
今天小編就為大家分享一篇用Python實(shí)現(xiàn)數(shù)據(jù)的透視表的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-10-10解決python 兩個(gè)時(shí)間戳相減出現(xiàn)結(jié)果錯(cuò)誤的問題
這篇文章主要介紹了解決python 兩個(gè)時(shí)間戳相減出現(xiàn)結(jié)果錯(cuò)誤的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03解決python?pip安裝第三方模塊報(bào)錯(cuò):error:legacy-install-failure
pip是python的第三方庫(kù)管理器,可以根據(jù)所開發(fā)項(xiàng)目的需要,使用pip相關(guān)命令安裝不同庫(kù),下面這篇文章主要給大家介紹了關(guān)于解決python?pip安裝第三方模塊報(bào)錯(cuò):error:?legacy?-?install?-?failure的相關(guān)資料,需要的朋友可以參考下2023-04-04