脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - 基于Python3制作一个带GUI界面的小说爬虫工具

基于Python3制作一个带GUI界面的小说爬虫工具

2022-09-12 11:45mortimer Python

这篇文章主要为大家介绍了一个通过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"[[]#/:*,;?""<>|()《》&^!~=%{}@!:。·!¥……() ]","",text)

# 入口
def main():
    global cjstatus, proxies, threadNum, pool_sema
    sg.theme("reddit")
    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")
        ],
    ]
    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("已停止...点击重新开始")
                continue
            window["error"].update("", visible=False)
            urls = values["url"].strip().split("
")
            lenth = len(urls)
            for k, url in enumerate(urls):
                if (not re.match(r"%sd+_d+/" % baseurl, url.strip())):
                    if len(url.strip()) > 0:
                        window["error"].update("地址错误:%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"]
                }
            # 线程数量
            if values["threadnum"] and int(values["threadnum"]) > 0:
                threadNum = int(values["threadnum"])
            pool_sema = threading.BoundedSemaphore(threadNum)
            cjstatus = True
            window["start"].update("采集中...点击停止")
            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()+"
"+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, "
请求 %s 错误,原因:%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, "
请求%s错误,原因:%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, "
请求%s:%s错误,原因:%s" % (zjname, zjurl, zjpage.reason)))
            continue

        if zjpage.status_code != 200:
            window.write_event_value("-THREAD-", (threading.current_thread(
            ).name, "
请求%s:%s错误,原因:%s" % (zjname, zjurl, zjpage.reason)))
            return 
        
        zjpage.encoding = "utf-8"
        zjpage_content = etree.HTML(zjpage.text).xpath("//div[@id="content"]/text()")
        content = "
【"+zjname+"】
"
        for _ in zjpage_content:
            content += _.strip() + "
"
        with open(bookfilename, "a+", encoding="utf-8") as fs:
            fs.write(content)
            window.write_event_value(
                "-THREAD-", (threading.current_thread().name, "
%s:%s 采集成功" % (bookname, zjname)))
        time.sleep(random.uniform(0.05, 0.2))

    # 下载完毕
    window.write_event_value("-THREAD-", (threading.current_thread(
    ).name, "
请求 %s 结束" % page_url))
    pool_sema.release()


if __name__ == "__main__":
    main()

以上就是基于Python3制作一个带GUI界面的小说爬虫工具的详细内容,更多关于Python3小说爬虫工具的资料请关注服务器之家其它相关文章!

原文链接:https://juejin.cn/post/7061603255616274462

延伸 · 阅读

精彩推荐
  • PythonPython实现检测服务器是否可以ping通的2种方法

    Python实现检测服务器是否可以ping通的2种方法

    这篇文章主要介绍了Python实现检测服务器是否可以ping通的2种方法,本文分别讲解了使用ping和fping命令检测服务器是否可以ping通,需要的朋友可以参考下 ...

    脚本之家13422020-05-18
  • PythonPython抽象和自定义类定义与用法示例

    Python抽象和自定义类定义与用法示例

    这篇文章主要介绍了Python抽象和自定义类定义与用法,结合实例形式分析了Python抽象方法、抽象类相关功能、定义、用法及相关操作注意事项,需要的朋友可...

    学习不止于前6372021-03-29
  • Pythonpython 如何获取页面所有a标签下href的值

    python 如何获取页面所有a标签下href的值

    这篇文章主要介绍了python 获取页面所有a标签下href的值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    不愿透露姓名的菜鸟10822021-10-25
  • PythonPython字符串中查找子串小技巧

    Python字符串中查找子串小技巧

    这篇文章主要介绍了Python字符串中查找子串小技巧,,需要的朋友可以参考下 ...

    脚本之家18072020-06-03
  • PythonPython 开发神技 -- 使用管道 Pipe

    Python 开发神技 -- 使用管道 Pipe

    众所周知,Pytnon 非常擅长处理数据,尤其是后期数据的清洗工作。今天派森酱就给大家介绍一款处理数据的神器 Pipe。...

    Python编程10952021-12-31
  • PythonPython注释详解

    Python注释详解

    下面小编就为大家带来一篇Python注释详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Python教程网5532020-08-24
  • PythonPython Pandas数据合并pd.merge用法详解

    Python Pandas数据合并pd.merge用法详解

    在合并数据的操作中,除了pd.concat()函数,另一个常用的函数就是pd.merge()了,下面这篇文章主要给大家介绍了关于Python Pandas数据合并pd.merge用法的相关资料,需要...

    山茶花开时。7792022-08-26
  • PythonPython FTP两个文件夹间的同步实例代码

    Python FTP两个文件夹间的同步实例代码

    本文通过实例代码给大家介绍了python ftp两个文件夹间的同步,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧...

    昵称最烦了6552021-02-25