How to cancel or pause a urllib request in python

南楼画角 提交于 2021-01-29 12:58:57

问题


So I have this program which requests a file from the web and the user can download it. I am using urllib.request and tkinter for my program. The problem is that when the user hits the 'Download' button there is no pause or cancel until the file gets downloaded and the program freezes too. I really want to create a pause or a cancel button, but I do not know how and I want to eliminate the freezing of the program. Should I use another library like 'requests'? Or should I try threading? Can someone guide me through this? My code(BTW if you know any way to improve my program I would appreciate it a lot if you shared it with me):

from tkinter import *
from tkinter import font as tkFont
import random
import urllib.request
import requests
from tqdm import tqdm
from tqdm.auto import tqdm


def printsth():
    print("Yay it works! ")


def main_menu():
    root = Tk()
    # the top menu
    num = IntVar()
    # var = IntVar()
    menu = Menu(root)
    root.config(menu=menu)
    submenu = Menu(menu)
    menu.add_cascade(label="Settings", menu=submenu)

    def custom_op():
        custom = Tk()

        custom.mainloop()
    submenu.add_command(label="Customization ", command=custom_op)

    def settings_op():
        set_win = Tk()

        set_win.mainloop()
    submenu.add_command(label="Settings ", command=settings_op)
    submenu.add_separator()
    submenu.add_command(label="Exit", command=root.destroy)

    # the edit menu
    editmenu = Menu(menu)
    menu.add_cascade(label="Edit", menu=editmenu)
    editmenu.add_command(label="Redo...", command=printsth)

    # the tool bar
    toolbar = Frame(root, bg="light gray")
    insert_button = Button(toolbar, text="Insert an image", command=printsth)
    insert_button.pack(side=LEFT, padx=2, pady=2)
    print_button = Button(toolbar, text="Print", command=printsth)
    print_button.pack(side=LEFT, padx=2, pady=2)
    toolbar.pack(side=TOP, fill=X)

    # the download function
    def download_image():
        global formatname
        if num.get() == 1:
            name = random.randrange(1, 100000)
        else:
            name = str(name_entry.get())
        formatname = str(format_entry.get())
        '''if var.get() == 1:
            operator = str(url_entry.get())
            formatname = '.' + operator[-3] + operator[-2] + operator[-1]
        else:
            pass'''
        fullname = str(name) + formatname
        url = str(url_entry.get())
        fw = open('file-size.txt', 'w')
        file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
        fw.write(str(file_size))
        fw.close()
        path = str(output_entry.get()) + "\\"
        urllib.request.urlretrieve(url, path.replace("\\", "\\\\") + fullname)

    # the status bar
    status_bar = Label(root, text="Downloading...", bd=1, relief=SUNKEN, anchor=W)
    status_bar.pack(side=BOTTOM, fill=X)

    # the download frame
    body_frame = Frame(root, bg="light blue")
    download_button = Button(body_frame, text="Download! ", command=download_image, border=3, width=20, height=5)
    download_design = tkFont.Font(size=12, slant='italic')
    download_button['font'] = download_design
    download_button.pack(side=LEFT, pady=5, padx=5)
    body_frame.pack(side=LEFT, fill=Y)
    # the main interaction menu
    inter_frame = Frame(root)
    url_entry = Entry(inter_frame)
    label = Label(inter_frame, text="Enter the image URL: ")
    file_format = Label(inter_frame, text="Choose your file format: ")
    format_entry = Entry(inter_frame)
    file_name = Label(inter_frame, text="File's name: ")
    name_entry = Entry(inter_frame)
    check_name = Checkbutton(inter_frame, text="Give a random name", variable=num)
    # check_format = Checkbutton(inter_frame, text="Download with default format", variable=var)
    output_path = Label(inter_frame, text="Choose output path: ")
    output_entry = Entry(inter_frame)
    file_name.pack(anchor=CENTER, expand=1)
    name_entry.pack(anchor=CENTER, expand=1)
    check_name.pack(anchor=CENTER, expand=1)
    label.pack(anchor=CENTER, expand=1)
    url_entry.pack(anchor=CENTER, expand=1)
    file_format.pack(anchor=CENTER, expand=1)
    format_entry.pack(anchor=CENTER, expand=1)
    # check_format.pack(anchor=CENTER)
    output_path.pack(anchor=CENTER, expand=1)
    output_entry.pack(anchor=CENTER, expand=1)
    inter_frame.pack(expand=1)
    root.mainloop()

    # the end!


main_menu()

回答1:


You can use reporthook option of urllib.request.urlretrieve() to associate a callback and abort the download by raising exception inside the callback:

downloading = False   # flag to indicate whether download is active

def download_progress(count, blksize, filesize):
    nonlocal downloading
    if downloading:
        downloaded = count * blksize
        print('downloaded %s / %s' % (downloaded, filesize))
        root.update()  # let user interact with the GUI
    else:
        # user selects to abort the download
        raise Exception('download aborted!')

# the download function
def download_image():
    global formatname
    nonlocal downloading
    if downloading:
        downloading = False
        return
    download_button.config(text='Stop!')  # let user to click the button to abort download
    downloading = True
    if num.get() == 1:
        name = random.randrange(1, 100000)
    else:
        name = str(name_entry.get())
    formatname = str(format_entry.get())
    '''if var.get() == 1:
        operator = str(url_entry.get())
        formatname = '.' + operator[-3] + operator[-2] + operator[-1]
    else:
        pass'''
    fullname = str(name) + formatname
    url = str(url_entry.get())
    fw = open('file-size.txt', 'w')
    file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
    fw.write(str(file_size))
    fw.close()
    path = str(output_entry.get()) + "\\"
    try:
        urllib.request.urlretrieve(url, path.replace("\\", "\\\\")+fullname, download_progress)  # added reporthook callback
    except Exception as e:
        print(e)  # download aborted
    else:
        print('done')
    download_button.config(text='Download!')  # resume download button

The text of download_button is changed to Stop! after it is clicked so that user can click it again to abort the download. When the download is aborted/completed, its text is changed back to "Download!".



来源:https://stackoverflow.com/questions/61193811/how-to-cancel-or-pause-a-urllib-request-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!