基于Python3制作一個(gè)帶GUI界面的小說爬蟲工具
效果圖
最近幫朋友寫個(gè)簡單爬蟲,順便整理了下,搞成了一個(gè)帶GUI界面的小說爬蟲工具,用來從筆趣閣爬取小說。
開發(fā)完成后的界面
采集過程界面
采集后存儲(chǔ)
主要功能
1.多線程采集,一個(gè)線程采集一本小說
2.支持使用代理,尤其是多線程采集時(shí),不使用代理可能封ip
3.實(shí)時(shí)輸出采集結(jié)果
使用 threading.BoundedSemaphore() pool_sema.acquire() pool_sema.release()
來限制線程數(shù)量,防止并發(fā)線程過。具體限制數(shù)量,可在軟件界面輸入,默認(rèn)5個(gè)線程
# 所有線程任務(wù)開始前 pool_sema.threading.BoundedSemaphore(5) # 具體每個(gè)線程開始前 鎖 pool_sema.acquire() .... # 線程任務(wù)執(zhí)行結(jié)束釋放 pol_sema.release()
用到的第三方模塊
pip install requests pip install pysimplegui pip install lxml pip install pyinstaller
GUI 界面使用了一個(gè)tkinter 的封裝庫 PySimpleGUI
, 使用非常方便,雖然界面不夠漂亮,但勝在簡單,非常適合開發(fā)些小工具。https://pysimplegui.readthedocs.io/en/latest/比如這個(gè)界面的布局,只需簡單幾個(gè) list
layout = [ [sg.Text('輸入要爬取的小說網(wǎng)址,點(diǎn)此打開筆趣閣站點(diǎn)復(fù)制', font=("微軟雅黑", 12), key="openwebsite", enable_events=True, tooltip="點(diǎn)擊在瀏覽器中打開")], [sg.Text("小說目錄頁url,一行一個(gè):")], [ sg.Multiline('', key="url", size=(120, 6), autoscroll=True, expand_x=True, right_click_menu=['&Right', ['粘貼']] ) ], [sg.Text(visible=False, text_color="#ff0000", key="error")], [ sg.Button(button_text='開始采集', key="start", size=(20, 1)), sg.Button(button_text='打開下載目錄', key="opendir", size=(20, 1), button_color="#999999") ], [sg.Text('填寫ip代理,有密碼格式 用戶名:密碼@ip:端口,無密碼格式 ip:端口。如 demo:123456@123.1.2.8:8580')], [ sg.Input('', key="proxy"), sg.Text('線程數(shù)量:'), sg.Input('5', key="threadnum"), ], [ sg.Multiline('等待采集', key="res", disabled=True, border_width=0, background_color="#ffffff", size=( 120, 6), no_scrollbar=False, autoscroll=True, expand_x=True, expand_y=True, font=("宋體", 10), text_color="#999999") ], ]
打包為 exe 命令
pyinstaller -Fw start.py
全部源碼
import time import requests import os import sys import re import random from lxml import etree import webbrowser import PySimpleGUI as sg import threading # user-agent header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36" } # 代理 proxies = {} # 刪除書名中特殊符號(hào) # 筆趣閣基地址 baseurl = 'https://www.xbiquwx.la/' # 線程數(shù)量 threadNum = 6 pool_sema = None THREAD_EVENT = '-THREAD-' cjstatus = False # txt存儲(chǔ)目錄 filePath = os.path.abspath(os.path.join(os.getcwd(), 'txt')) if not os.path.exists(filePath): os.mkdir(filePath) # 刪除特殊字符 def deletetag(text): return re.sub(r'[\[\]#\/\\:*\,;\?\"\'<>\|\(\)《》&\^!~=%\{\}@?。??!ぃ。ぁǎ?]','',text) # 入口 def main(): global cjstatus, proxies, threadNum, pool_sema sg.theme("reddit") layout = [ [sg.Text('輸入要爬取的小說網(wǎng)址,點(diǎn)此打開筆趣閣站點(diǎn)復(fù)制', font=("微軟雅黑", 12), key="openwebsite", enable_events=True, tooltip="點(diǎn)擊在瀏覽器中打開")], [sg.Text("小說目錄頁url,一行一個(gè):")], [ sg.Multiline('', key="url", size=(120, 6), autoscroll=True, expand_x=True, right_click_menu=['&Right', ['粘貼']] ) ], [sg.Text(visible=False, text_color="#ff0000", key="error")], [ sg.Button(button_text='開始采集', key="start", size=(20, 1)), sg.Button(button_text='打開下載目錄', key="opendir", size=(20, 1), button_color="#999999") ], [sg.Text('填寫ip代理,有密碼格式 用戶名:密碼@ip:端口,無密碼格式 ip:端口。如 demo:123456@123.1.2.8:8580')], [ sg.Input('', key="proxy"), sg.Text('線程數(shù)量:'), sg.Input('5', key="threadnum"), ], [ sg.Multiline('等待采集', key="res", disabled=True, border_width=0, background_color="#ffffff", size=( 120, 6), no_scrollbar=False, autoscroll=True, expand_x=True, expand_y=True, font=("宋體", 10), text_color="#999999") ], ] window = sg.Window('采集筆趣閣小說', layout, size=(800, 500), resizable=True,) while True: event, values = window.read() if event == sg.WIN_CLOSED or event == 'close': # if user closes window or clicks cancel break if event == "openwebsite": webbrowser.open('%s' % baseurl) elif event == 'opendir': os.system('start explorer ' + filePath) elif event == 'start': if cjstatus: cjstatus = False window['start'].update('已停止...點(diǎn)擊重新開始') continue window['error'].update("", visible=False) urls = values['url'].strip().split("\n") lenth = len(urls) for k, url in enumerate(urls): if (not re.match(r'%s\d+_\d+/' % baseurl, url.strip())): if len(url.strip()) > 0: window['error'].update("地址錯(cuò)誤:%s" % url, visible=True) del urls[k] if len(urls) < 1: window['error'].update( "每行地址需符合 %s84_84370/ 形式" % baseurlr, visible=True) continue # 代理 if len(values['proxy']) > 8: proxies = { "http": "http://%s" % values['proxy'], "https": "http://%s" % values['proxy'] } # 線程數(shù)量 if values['threadnum'] and int(values['threadnum']) > 0: threadNum = int(values['threadnum']) pool_sema = threading.BoundedSemaphore(threadNum) cjstatus = True window['start'].update('采集中...點(diǎn)擊停止') window['res'].update('開始采集') for url in urls: threading.Thread(target=downloadbybook, args=( url.strip(), window,), daemon=True).start() elif event == "粘貼": window['url'].update(sg.clipboard_get()) print("event", event) if event == THREAD_EVENT: strtext = values[THREAD_EVENT][1] window['res'].update(window['res'].get()+"\n"+strtext) cjstatus = False window.close() #下載 def downloadbybook(page_url, window): try: bookpage = requests.get(url=page_url, headers=header, proxies=proxies) except Exception as e: window.write_event_value( '-THREAD-', (threading.current_thread().name, '\n請(qǐng)求 %s 錯(cuò)誤,原因:%s' % (page_url, e))) return if not cjstatus: return # 鎖線程 pool_sema.acquire() if bookpage.status_code != 200: window.write_event_value( '-THREAD-', (threading.current_thread().name, '\n請(qǐng)求%s錯(cuò)誤,原因:%s' % (page_url, page.reason))) return bookpage.encoding = 'utf-8' page_tree = etree.HTML(bookpage.text) bookname = page_tree.xpath('//div[@id="info"]/h1/text()')[0] bookfilename = filePath + '/' + deletetag(bookname)+'.txt' zj_list = page_tree.xpath( '//div[@class="box_con"]/div[@id="list"]/dl/dd') for _ in zj_list: if not cjstatus: break zjurl = page_url + _.xpath('./a/@href')[0] zjname = _.xpath('./a/@title')[0] try: zjpage = requests.get( zjurl, headers=header, proxies=proxies) except Exception as e: window.write_event_value('-THREAD-', (threading.current_thread( ).name, '\n請(qǐng)求%s:%s錯(cuò)誤,原因:%s' % (zjname, zjurl, zjpage.reason))) continue if zjpage.status_code != 200: window.write_event_value('-THREAD-', (threading.current_thread( ).name, '\n請(qǐng)求%s:%s錯(cuò)誤,原因:%s' % (zjname, zjurl, zjpage.reason))) return zjpage.encoding = 'utf-8' zjpage_content = etree.HTML(zjpage.text).xpath('//div[@id="content"]/text()') content = "\n【"+zjname+"】\n" for _ in zjpage_content: content += _.strip() + '\n' with open(bookfilename, 'a+', encoding='utf-8') as fs: fs.write(content) window.write_event_value( '-THREAD-', (threading.current_thread().name, '\n%s:%s 采集成功' % (bookname, zjname))) time.sleep(random.uniform(0.05, 0.2)) # 下載完畢 window.write_event_value('-THREAD-', (threading.current_thread( ).name, '\n請(qǐng)求 %s 結(jié)束' % page_url)) pool_sema.release() if __name__ == '__main__': main()
以上就是基于Python3制作一個(gè)帶GUI界面的小說爬蟲工具的詳細(xì)內(nèi)容,更多關(guān)于Python3小說爬蟲工具的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Pycharm Available Package無法顯示/安裝包的問題Error Loading Package Li
這篇文章主要介紹了Pycharm Available Package無法顯示/安裝包的問題Error Loading Package List解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09python防止程序超時(shí)的實(shí)現(xiàn)示例
因?yàn)槟硞€(gè)需求,需要在程序運(yùn)行的時(shí)候防止超時(shí),本文主要介紹了python防止程序超時(shí)的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08TensorFlow實(shí)現(xiàn)模型評(píng)估
這篇文章主要為大家詳細(xì)介紹了TensorFlow實(shí)現(xiàn)模型評(píng)估,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09Django用戶認(rèn)證系統(tǒng) 組與權(quán)限解析
這篇文章主要介紹了Django用戶認(rèn)證系統(tǒng) 組與權(quán)限解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08python利用joblib進(jìn)行并行數(shù)據(jù)處理的代碼示例
在數(shù)據(jù)量比較大的情況下,數(shù)據(jù)預(yù)處理有時(shí)候會(huì)非常耗費(fèi)時(shí)間,可以利用 joblib 中的 Parallel 和 delayed 進(jìn)行多CPU并行處理,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-10-10python中DataFrame常用的描述性統(tǒng)計(jì)分析方法詳解
這篇文章主要介紹了python中DataFrame常用的描述性統(tǒng)計(jì)分析方法詳解,描述性統(tǒng)計(jì)分析是通過圖表或數(shù)學(xué)方法,對(duì)數(shù)據(jù)資料進(jìn)行整理、分析,并對(duì)數(shù)據(jù)的分布狀態(tài)、數(shù)字特征和隨機(jī)變量之間的關(guān)系進(jìn)行估計(jì)和描述的方法,需要的朋友可以參考下2023-07-07Python新版極驗(yàn)驗(yàn)證碼識(shí)別驗(yàn)證碼教程詳解
這篇文章主要介紹了Python新版極驗(yàn)驗(yàn)證碼識(shí)別驗(yàn)證碼,極驗(yàn)驗(yàn)證是一種在計(jì)算機(jī)領(lǐng)域用于區(qū)分自然人和機(jī)器人的,通過簡單集成的方式,為開發(fā)者提供安全、便捷的云端驗(yàn)證服務(wù)2023-02-02