热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何使用Python3制作一个带GUI界面的小说爬虫工具

这篇文章主要介绍如何使用Python3制作一个带GUI界面的小说爬虫工具,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!效果

这篇文章主要介绍如何使用Python3制作一个带GUI界面的小说爬虫工具,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

    效果图

    最近帮朋友写个简单爬虫,顺便整理了下,搞成了一个带GUI界面的小说爬虫工具,用来从笔趣阁爬取小说。

    开发完成后的界面

    如何使用Python3制作一个带GUI界面的小说爬虫工具

    采集过程界面

    如何使用Python3制作一个带GUI界面的小说爬虫工具

    采集后存储

    如何使用Python3制作一个带GUI界面的小说爬虫工具

    主要功能

    1.多线程采集,一个线程采集一本小说

    2.支持使用代理,尤其是多线程采集时,不使用代理可能封ip

    如何使用Python3制作一个带GUI界面的小说爬虫工具

    3.实时输出采集结果

    如何使用Python3制作一个带GUI界面的小说爬虫工具

    使用 threading.BoundedSemaphore() pool_sema.acquire() pool_sema.release() 来限制线程数量,防止并发线程过。具体限制数量,可在软件界面输入,默认5个线程

    如何使用Python3制作一个带GUI界面的小说爬虫工具

    # 所有线程任务开始前
    pool_sema.threading.BoundedSemaphore(5)
    
    # 具体每个线程开始前 锁
    pool_sema.acquire()  
    ....
    # 线程任务执行结束释放
    pol_sema.release()

    用到的第三方模块

    pip install requests
    pip install pysimplegui
    pip install lxml
    pip install pyinstaller

    GUI 界面使用了一个tkinter 的封装库 PySimpleGUI, 使用非常方便,虽然界面不够漂亮,但胜在简单,非常适合开发些小工具。https://pysimplegui.readthedocs.io/en/latest/比如这个界面的布局,只需简单几个 list

    layout = [
            [sg.Text('输入要爬取的小说网址,点此打开笔趣阁站点复制', fOnt=("微软雅黑", 12),
                     key="openwebsite", enable_events=True, tooltip="点击在浏览器中打开")],
            [sg.Text("小说目录页url,一行一个:")],
            [
                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('线程数量:'),
                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 = {}
    # 删除书名中特殊符号
    # 笔趣阁基地址
    baseurl = 'https://www.xbiquwx.la/'
    # 线程数量
    threadNum = 6
    pool_sema = None
    THREAD_EVENT = '-THREAD-'
    cjstatus = False
    
    # txt存储目录
    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&#39;[\[\]#\/\\:*\,;\?\"\&#39;<>\|\(\)《》&\^!~=%\{\}@!:。·!¥……() ]&#39;,&#39;&#39;,text)
    
    # 入口
    def main():
        global cjstatus, proxies, threadNum, pool_sema
        sg.theme("reddit")
        layout = [
            [sg.Text(&#39;输入要爬取的小说网址,点此打开笔趣阁站点复制&#39;, fOnt=("微软雅黑", 12),
                     key="openwebsite", enable_events=True, tooltip="点击在浏览器中打开")],
            [sg.Text("小说目录页url,一行一个:")],
            [
                sg.Multiline(&#39;&#39;, key="url", size=(120, 6), autoscroll=True, expand_x=True, right_click_menu=[&#39;&Right&#39;, [&#39;粘贴&#39;]]
                             )
            ],
            [sg.Text(visible=False, text_color="#ff0000", key="error")],
            [
                sg.Button(button_text=&#39;开始采集&#39;, key="start", size=(20, 1)),
                sg.Button(button_text=&#39;打开下载目录&#39;, key="opendir",
                          size=(20, 1), button_color="#999999")
            ],
            [sg.Text(&#39;填写ip代理,有密码格式 用户名:密码@ip:端口,无密码格式 ip:端口。如 demo:123456@123.1.2.8:8580&#39;)],
            [
                sg.Input(&#39;&#39;, key="proxy"),
                sg.Text(&#39;线程数量:&#39;),
                sg.Input(&#39;5&#39;, key="threadnum"),
            ],
            [
                sg.Multiline(&#39;等待采集&#39;, 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(&#39;采集笔趣阁小说&#39;, layout, size=(800, 500), resizable=True,)
        while True:
            event, values = window.read()
            if event == sg.WIN_CLOSED or event == &#39;close&#39;:  # if user closes window or clicks cancel
                break
            if event == "openwebsite":
                webbrowser.open(&#39;%s&#39; % baseurl)
            elif event == &#39;opendir&#39;:
                os.system(&#39;start explorer &#39; + filePath)
            elif event == &#39;start&#39;:
                if cjstatus:
                    cjstatus = False
                    window[&#39;start&#39;].update(&#39;已停止...点击重新开始&#39;)
                    continue
                window[&#39;error&#39;].update("", visible=False)
                urls = values[&#39;url&#39;].strip().split("\n")
                lenth = len(urls)
                for k, url in enumerate(urls):
                    if (not re.match(r&#39;%s\d+_\d+/&#39; % baseurl, url.strip())):
                        if len(url.strip()) > 0:
                            window[&#39;error&#39;].update("地址错误:%s" % url, visible=True)
                        del urls[k]
    
                if len(urls) < 1:
                    window[&#39;error&#39;].update(
                        "每行地址需符合 %s84_84370/ 形式" % baseurlr, visible=True)
                    continue
                # 代理
                if len(values[&#39;proxy&#39;]) > 8:
                    proxies = {
                        "http": "http://%s" % values[&#39;proxy&#39;],
                        "https": "http://%s" % values[&#39;proxy&#39;]
                    }
                # 线程数量
                if values[&#39;threadnum&#39;] and int(values[&#39;threadnum&#39;]) > 0:
                    threadNum = int(values[&#39;threadnum&#39;])
                pool_sema = threading.BoundedSemaphore(threadNum)
                cjstatus = True
                window[&#39;start&#39;].update(&#39;采集中...点击停止&#39;)
                window[&#39;res&#39;].update(&#39;开始采集&#39;)
    
                for url in urls:
                    threading.Thread(target=downloadbybook, args=(
                        url.strip(), window,), daemon=True).start()
            elif event == "粘贴":
                window[&#39;url&#39;].update(sg.clipboard_get())
    
            print("event", event)
            if event == THREAD_EVENT:
                strtext = values[THREAD_EVENT][1]
                window[&#39;res&#39;].update(window[&#39;res&#39;].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(
                &#39;-THREAD-&#39;, (threading.current_thread().name, &#39;\n请求 %s 错误,原因:%s&#39; % (page_url, e)))
            return
        if not cjstatus:
            return
        # 锁线程
        pool_sema.acquire()
    
        if bookpage.status_code != 200:
            window.write_event_value(
                &#39;-THREAD-&#39;, (threading.current_thread().name, &#39;\n请求%s错误,原因:%s&#39; % (page_url, page.reason)))
            return
    
        bookpage.encoding = &#39;utf-8&#39;
        page_tree = etree.HTML(bookpage.text)
        bookname = page_tree.xpath(&#39;//div[@id="info"]/h2/text()&#39;)[0]
        bookfilename = filePath + &#39;/&#39; + deletetag(bookname)+&#39;.txt&#39;
        zj_list = page_tree.xpath(
            &#39;//div[@class="box_con"]/div[@id="list"]/dl/dd&#39;)
        for _ in zj_list:
            if not cjstatus:
                break
            zjurl = page_url + _.xpath(&#39;./a/@href&#39;)[0]
            zjname = _.xpath(&#39;./a/@title&#39;)[0]
            try:
                zjpage = requests.get(
                    zjurl, headers=header, proxies=proxies)
            except Exception as e:
                window.write_event_value(&#39;-THREAD-&#39;, (threading.current_thread(
                ).name, &#39;\n请求%s:%s错误,原因:%s&#39; % (zjname, zjurl, zjpage.reason)))
                continue
    
            if zjpage.status_code != 200:
                window.write_event_value(&#39;-THREAD-&#39;, (threading.current_thread(
                ).name, &#39;\n请求%s:%s错误,原因:%s&#39; % (zjname, zjurl, zjpage.reason)))
                return 
            
            zjpage.encoding = &#39;utf-8&#39;
            zjpage_content = etree.HTML(zjpage.text).xpath(&#39;//div[@id="content"]/text()&#39;)
            content = "\n【"+zjname+"】\n"
            for _ in zjpage_content:
                content += _.strip() + &#39;\n&#39;
            with open(bookfilename, &#39;a+&#39;, encoding=&#39;utf-8&#39;) as fs:
                fs.write(content)
                window.write_event_value(
                    &#39;-THREAD-&#39;, (threading.current_thread().name, &#39;\n%s:%s 采集成功&#39; % (bookname, zjname)))
            time.sleep(random.uniform(0.05, 0.2))
    
        # 下载完毕
        window.write_event_value(&#39;-THREAD-&#39;, (threading.current_thread(
        ).name, &#39;\n请求 %s 结束&#39; % page_url))
        pool_sema.release()
    
    
    if __name__ == &#39;__main__&#39;:
        main()

    以上是“如何使用Python3制作一个带GUI界面的小说爬虫工具”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程笔记行业资讯频道!


    推荐阅读
    • XML介绍与使用的概述及标签规则
      本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
    • android listview OnItemClickListener失效原因
      最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
    • iOS超签签名服务器搭建及其优劣势
      本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
    • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
    • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
    • 向QTextEdit拖放文件的方法及实现步骤
      本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
    • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
    • CSS3选择器的使用方法详解,提高Web开发效率和精准度
      本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
    • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
    • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
    • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
      文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
    • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
      本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
    • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
      转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
    • 1.直接在cmd窗口运行pipinstalljieba2.使用conda自带的安装工具condainstalljieba3.有一些模块是无法使用以上两种方式安装上ÿ ... [详细]
    • EzPP 0.2发布,新增YAML布局渲染功能
      EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
    author-avatar
    手机用户2502885835
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有