吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1317|回复: 8
收起左侧

[求助] Python+Tkinter如何控制下载进度条

[复制链接]
Trojians 发表于 2023-3-31 14:29
起因:昨天逛论坛时,看到一位大佬@redballoon 写了一个“[学习记录] 91韩漫采集(异步协程)-- 打包成exe”91韩漫采集(异步协程)-- 打包成exe
https://www.52pojie.cn/thread-1767266-1-1.html
(出处: 吾爱破解论坛)
的帖子,而且也给提供了源代码,下载下来运行了一下,可以下载漫画。但是我想把它改写成GUI程序,现在程序可以正常下载漫画,但是我写的进度条没有工作。而且程序在运行时,会出现“未响应”的提示。
哪位大神或者老哥们路过,可以帮忙看看是怎么回事吗?
[Python] 纯文本查看 复制代码
# _*_ coding: utf-8 _*_
# @Time: 2023/3/28 23:25
# @Author: 🎈
# @GUI:Trojians
# @File: 91hanman


import aiohttp
import asyncio
import aiofiles
import requests
from urllib.parse import quote
from lxml import etree
import os
from re import sub
import tkinter as tk
import ttkbootstrap as ttk
import tkinter.messagebox
class MangaDownloaderGUI():
    def __init__(self, master):
        self.master = master
        master.geometry('600x371+{}+{}'.format(int((master.winfo_screenwidth()-600)/2), int((master.winfo_screenheight()-371)/2)))
        self.base_url = 'https://9y03.xyz'
        self.label1 = ttk.Label(master,text="请输入漫画名称:", bootstyle='SUCCESS',font=("Helvetica",16))
        self.label1.pack(pady=10)
        self.entry1 = ttk.Entry(master)
        self.entry1.pack(pady=10)
        self.button1 = ttk.Button(master,text="开始下载",command=self.start_download,style='SUCCESS.OUTLINE')
        self.button1.pack(pady=10)
        self.progress_var = tk.StringVar()
        self.progressbar = ttk.Progressbar(master, orient="horizontal", length=400, mode="determinate", variable=self.progress_var)
        self.progressbar.pack(pady=10)
    def get_page(self,url):
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54',
            'cookie': 'SL_G_WPT_TO=zh; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1',
            'referer': 'https://9y03.xyz/',
        }
        try:
            with requests.get(url, headers=headers, timeout=(20,50)) as response:
                if response.status_code == 200:
                    return response.text
                else:
                    return 'code error!'
        except ConnectionError as e:
            return
    def parse(self,html):
        dom_tree = etree.HTML(html)
        r_url = dom_tree.xpath('//p[@class="comic__title"]/a/@href')[0]
        detail_url = self.base_url + r_url
        detail_page = self.get_page(detail_url)
        detail_page_tree = etree.HTML(detail_page)
        lis = detail_page_tree.xpath('//div[@class="chapter__list clearfix"]/ul/li')
        for li in lis:
            chapter_link = li.xpath('./a/@href')[0]
            chapter_name = li.xpath('./a/text()')[0].strip()
            mango_url = self.base_url + chapter_link
            yield chapter_name, mango_url
    def get_chapter(self,title, pics_url):
        pic_page_html = self.get_page(pics_url)
        pic_page_tree = etree.HTML(pic_page_html)
        divs = pic_page_tree.xpath('/html/body/div[2]/div[5]')
        for div in divs:
            img_url = div.xpath('./div/img/@data-original')
            img_name = div.xpath('./div/img/@alt')
            yield list(zip(img_url, img_name))
    async def download(self,url, name, folder_path):
        async with aiohttp.ClientSession() as session:
            async with session.get(url)as response:
                img_content = await response.content.read()
                file_path = os.path.join(folder_path, name)
                async with aiofiles.open(file_path, mode='wb')as f:
                    await f.write(img_content)
                    await asyncio.sleep(0.1) 
                    self.progressbar.step(1) 
                    self.progress_var.set(f"下载进度:{self.progressbar['value']}%") # 更新进度条的文本显示
    async def main(self):
        kw = self.entry1.get()
        url = f'https://9y03.xyz/index.php/search?key={quote(kw)}'
        html = self.get_page(url)
        chapter_data = self.parse(html)
        for chapter_title, chapter_url in chapter_data:
            folder_path = f'{kw}\\'
            title = sub(r'[\\/:\*\?"<>\|]', '', chapter_title)
            folder_path = os.path.join(folder_path, title)
            os.path.exists(folder_path) or os.makedirs(folder_path)
            img_data = self.get_chapter(chapter_title, chapter_url)
            tasks = []
            num_tasks = 0
            for data in img_data:
                for pic_url, pic_name in data:
                    tasks.append(asyncio.ensure_future(self.download(pic_url, pic_name, folder_path)))
                    num_tasks += 1
            self.progressbar["maximum"] = num_tasks # 设置进度条的最大值
            self.progress_var.set("下载进度:0%") # 更新进度条的文本显示
            await asyncio.gather(*tasks)
    def start_download(self):
        asyncio.run(self.main())
root = ttk.Window("漫画下载程序 by redballoon GUI:Trojians","superhero")
my_gui = MangaDownloaderGUI(root)
root.mainloop()




新人第一次发帖,有写的不对的地方,望各位见谅。
截图.png

免费评分

参与人数 3吾爱币 +5 热心值 +3 收起 理由
whyerect + 3 + 1 我很赞同!
VXORBY + 1 + 1 谢谢@Thanks!
redballoon + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

狐白本白 发表于 2023-3-31 14:48
增加一个按钮 控制下载函数即可
admib木木 发表于 2023-3-31 16:11
这个问题可能是因为你的下载程序在主线程上运行,导致GUI程序出现“未响应”的提示。建议将下载代码放在单独的线程或进程中运行。

你可以使用Python的threading模块或multiprocessing模块来创建一个新的线程或进程,并在其中运行下载代码。这样,下载将在后台运行,而不会阻塞主GUI线程,从而避免了“未响应”的提示和进度条不工作的问题。

例如,可以将以下代码添加到您的MangaDownloaderGUI类中,以启动一个新的线程并运行下载程序:
import threading

def start_download_thread(self):
    t = threading.Thread(target=self.start_download)
    t.start()
然后,将您的“开始下载”按钮的命令设置为start_download_thread方法,而不是start_download方法:
self.button1 = ttk.Button(master,text="开始下载",command=self.start_download_thread,style='SUCCESS.OUTLINE')
这样,当用户单击“开始下载”按钮时,将启动一个新的线程来运行下载程序,GUI程序将继续响应用户输入和操作,并且您的进度条也应该工作正常了。

免费评分

参与人数 2吾爱币 +4 热心值 +2 收起 理由
whyerect + 3 + 1 膜拜大佬!
Trojians + 1 + 1 热心回复!感谢木木大佬,昨天没弄好,冷却24小时

查看全部评分

 楼主| Trojians 发表于 2023-3-31 16:21
admib木木 发表于 2023-3-31 16:11
这个问题可能是因为你的下载程序在主线程上运行,导致GUI程序出现“未响应”的提示。建议将下载代码放在单 ...

好的,我看明白了,我去试试,谢谢木木大佬
kit249 发表于 2023-3-31 17:05
正需要,一起学习,谢谢。
yiwangtang 发表于 2023-3-31 17:53
都是大神级别,厉害厉害&#128077;&#127995;&#128077;&#127995;&#128077;&#127995;&#128077;&#127995;&#128077;&#127995;&#128077;&#127995;&#128077;&#127995;
redballoon 发表于 2023-3-31 18:15
可以的,一起学习。哈哈
redballoon 发表于 2023-4-1 01:46

终于解决未响应问题了,还额外增加了个数据下载显示

import aiohttp
import asyncio
import aiofiles
import requests
from urllib.parse import quote
from lxml import etree
import os
from re import sub
import tkinter as tk
import ttkbootstrap as ttk
from tkinter import scrolledtext
from threading import Thread

class MangaDownloaderGUI():

    def __init__(self, master):
        self.master = master
        master.geometry('600x371+{}+{}'.format(int((master.winfo_screenwidth() - 600) / 2),
                                               int((master.winfo_screenheight() - 371) / 2)))
        self.base_url = 'https://9y03.xyz'
        self.label1 = ttk.Label(master, text="请输入漫画名称:", bootstyle='SUCCESS', font=("Helvetica", 16))
        self.label1.pack(pady=10)
        self.entry1 = ttk.Entry(master)
        self.entry1.pack(pady=10)
        self.button1 = ttk.Button(master, text="开始下载", command=self.start_download_thread, style='SUCCESS.OUTLINE')
        self.button1.pack(pady=10)
        self.progress_var = tk.StringVar()
        self.progressbar = ttk.Progressbar(master, orient="horizontal", length=400, mode="determinate",
                                           variable=self.progress_var)
        self.progressbar.pack(pady=10)

        self.frame = ttk.Frame(master)
        self.frame.pack(pady=20)
        self.scrolled_text = scrolledtext.ScrolledText(self.frame)
        self.scrolled_text.pack()

    def get_page(self, url):
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54',
            'cookie': 'SL_G_WPT_TO=zh; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1',
            'referer': 'https://9y03.xyz/',
        }
        try:
            with requests.get(url, headers=headers, timeout=(20, 50)) as response:
                if response.status_code == 200:
                    return response.text
                else:
                    return 'code error!'
        except ConnectionError as e:
            return

    def parse(self, html):
        dom_tree = etree.HTML(html)
        r_url = dom_tree.xpath('//p[@class="comic__title"]/a/@href')[0]
        detail_url = self.base_url + r_url
        detail_page = self.get_page(detail_url)
        detail_page_tree = etree.HTML(detail_page)
        lis = detail_page_tree.xpath('//div[@class="chapter__list clearfix"]/ul/li')
        for li in lis:
            chapter_link = li.xpath('./a/@href')[0]
            chapter_name = li.xpath('./a/text()')[0].strip()
            mango_url = self.base_url + chapter_link
            yield chapter_name, mango_url

    def get_chapter(self, title, pics_url):
        pic_page_html = self.get_page(pics_url)
        pic_page_tree = etree.HTML(pic_page_html)
        divs = pic_page_tree.xpath('/html/body/div[2]/div[5]')
        for div in divs:
            img_url = div.xpath('./div/img/@data-original')
            img_name = div.xpath('./div/img/@alt')
            yield list(zip(img_url, img_name))

    async def download(self, url, name, folder_path):
        async with aiohttp.ClientSession() as session:
            async with session.get(url)as response:
                img_content = await response.content.read()
                await asyncio.sleep(0)
                file_path = os.path.join(folder_path, name)
                async with aiofiles.open(file_path, mode='wb')as f:
                    await f.write(img_content)
                    await asyncio.sleep(0)
                    self.progressbar.step(1)
                    self.progress_var.set(f"下载进度:{self.progressbar['value']}%")  # 更新进度条的文本显示

    async def main(self):
        kw = self.entry1.get()
        url = f'https://9y03.xyz/index.php/search?key={quote(kw)}'
        html = self.get_page(url)
        chapter_data = self.parse(html)
        for chapter_title, chapter_url in chapter_data:
            folder_path = f'{kw}\\'
            title = sub(r'[\\/:\*\?"<>\|]', '', chapter_title)
            folder_path = os.path.join(folder_path, title)
            os.path.exists(folder_path) or os.makedirs(folder_path)
            img_data = self.get_chapter(chapter_title, chapter_url)
            tasks = []
            num_tasks = 0

            self.scrolled_text.insert(tk.END, f'正在下载>>> {title}' + '\n')

            for data in img_data:
                for pic_url, pic_name in data:
                    tasks.append(asyncio.create_task(self.download(pic_url, pic_name, folder_path)))
                    num_tasks += 1
            self.progressbar["maximum"] = num_tasks  # 设置进度条的最大值
            self.progress_var.set("下载进度:0%")  # 更新进度条的文本显示
            await asyncio.gather(*tasks)

    def start_download(self):
        # loop = asyncio.get_event_loop()
        # loop.run_until_complete(self.main())
        # 报错不在事件循环中, 解决是既然没有event loop,把程序最初的loop传递到thread中去:
        # asyncio.set_event_loop(loop) ,这个loop在程序主函数中保留好,传递到thread中去使用。
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.main())

    def start_download_thread(self, ):
        # 根据坛友 admib木木 的解答留言思路创建一个线程函数
        t = Thread(target=self.start_download)
        t.setDaemon(True)
        t.start()

root = ttk.Window("漫画下载程序 by redballoon GUI:Trojians", "superhero")
my_gui = MangaDownloaderGUI(root)
root.mainloop()

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
whyerect + 1 + 1 热心回复!

查看全部评分

shojnhv 发表于 2023-4-1 06:08
一起学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 23:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表