pdf批量下载工具制作_使用asyncio异步高速下载pdf

前言

   最近在学习进阶的python,学到tkinter,刚好在内网有一个需求,需要一个能根据一大批pdf下载链接,批量下载pdf文件的工具,当然网上也有很多类似功能的成熟软件。不过,毕竟是学过python的哈哈哈哈哈,还是要躁动一下的,所以写了一个pdf批量下载的小工具。
  这篇文章将会学到的知识点
  1️⃣asynico异步下载方法,可用于提高爬虫效率;
  2️⃣tkinter的初级功能部件:Label(标签),Button(按钮),主窗口关闭(root),filedialog(打开文件窗口),askdirectory(保存文件路径窗口),text部件,Entry部件的使用,窗口显示正中间的方法。
  3️⃣爬虫下载时候强制跳过签名验证。
  python环境:win10 64位环境,python3.83版本的。

零、设计思路

   核心的代码其实是使用了asynico的异步功能,肥肠非常强大,💪质的飞跃可以说💪,可以看下使用asynico不使用asynico的区别👇
❗️❗️这是使用asynico的下载10个pdf文件只用2.3秒。
在这里插入图片描述
❕ ❕这是不使用asynico的情况,下载同样的10个pdf文件,用时12秒。

在这里插入图片描述
当时被这个速度感动到了😂😂,所以下定决心一定要掌握这个技能。💪💪
主要的逻辑和实现效果如下:
主要的逻辑:
主体思路
实现效果:
在这里插入图片描述

如果想了解学习这个异步功能就请继续往下看吧。💪

一、核心代码

   代码来说,难度可以说是很低了,非常适合python的初级练习项目。主要的代码有两个:

(一)tkinter框架代码

import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import time

def save_file():
    global store_path
    store_path = filedialog.askdirectory()

# 创建主窗口
root = tk.Tk()
# 下载器的名称
root.title('PDF链接批量下载工具')
# 进行居中显示
max_w, max_h = root.maxsize()
root.geometry(f'300x150+{int((max_w - 300) / 2)}+{int((max_h - 150) / 2)}')  # 居中显示
# 固定窗口尺寸不能修改
root.resizable(width=False, height=False)

# 创建输入窗
entry1 = tk.Entry(root)
entry1.place(relx=0.5, rely=0.5, width=100, anchor='center')


# 选择文件标签
lab1 = tk.Label(root, text='选择文件:')
lab1.place(relx=0.35, rely=0.5, anchor='e')

# 创建打开文件函数
def openFile():
    global text_path
    text_path = filedialog.askopenfilename(filetypes=[('文本', '.txt')])
    # 关闭之前的窗口
    root.destroy()
    # 创建新窗口
    root1 = tk.Tk()
    max_w1, max_h1 = root1.maxsize()
    root1.geometry(f'+{int((max_w1 - 600) / 2)}+{int((max_h1 - 500) / 2)}')  # 居中显示
    # 创建scrollbar
    sb = tk.Scrollbar(root1)
    sb.grid(column=3, sticky='NS')
    # 创建text窗口
    text = tk.Text(root1, yscrollcommand=sb.set)  # yscrollcommand绑定sb的设置
    text.grid(row=0, column=0, columnspan=3)
    sb.config(command=text.yview)
    f = open(text_path, 'r', encoding='utf-8')
    text.insert('end', f.read())
    f.seek(0) # 光标移到开始位置
    # 文件个数
    global pdf_num
    pdf_num = len(f.readlines())
    # 创建标签
    lb = tk.Label(root1, text=f'总共有{pdf_num}个文件。')
    lb.grid(row=1, column=0)
    # 选择下载的位置
    button0 = tk.Button(root1, text='选择保存位置', command=save_file)
    button0.grid(row=1, column=1, pady=3)
    # 创建确认按钮
    button1 = tk.Button(root1, text='确认开始下载', width=10, command=run_async) # <1>总控制函数
    button1.grid(row=1, column=2, pady=3)
    root1.mainloop()
# 创建获取文件路径按钮
b1 = tk.Button(root, text='获取文件', command=openFile)
b1.place(relx=0.7, rely=0.5, anchor='w')
tk.mainloop()

可以看到,在 <1> 处缺少一个总的下载控制函数的定义,接下来就是关于使用asyncio进行异步下载的的代码了:

(二)使用asyncio下载的代码

   这里需要稍微解释一下asyncio异步下载的原理:(个人理解)
   顺序下载: 一般来说,我们就直接通过请求->反馈->下载存储这样的顺序来批量下载pdf,然后加一个循环进行线性下载,平时都是这样的,有个缺点就是,当你的某一个文件因为太大,在I/O阶段就有可能被阻塞,然后就会一直等待,直到完成存储进行下一个下载任务。
  ok,那你怎么提高下载的效率呢?所以我们就会有三个解决方案:
  ①使用多线程threading;既然一个下载线程慢,那就搞多几个嘛;
  ②异步下载,就是既然卡在那里,那我就不等你了,我继续下载其他文件,等你下载好了再告诉我一声,回来再下载,需要注意的是:异步下载是无序的。
  ③多线程+异步,这个简直是下载和执行任务的王炸手段。还没掌握。。。
   这里主要学习第二个方法:异步下载

import asyncio  # 异步下载包也就是协程函数
import aiohttp

# 创建下载函数
async def pdfdownload(session, pdfurl, name, filespath):
    # 因为你在下载的时候会遇到一些验证或者警告的提示,你可以使用verify_ssl=False语句进行强制不显示该警告
    async with session.get(pdfurl, verify_ssl=False) as re:
        with open(f'{filespath}' + f'{name}' + ".pdf", 'wb') as f1:
            while True:
                chunk = await re.content.read(1024)
                if not chunk:
                    break
                f1.write(chunk)
 
# 创建开始下载函数
async def start_download():
    s1 = time.time()
    async with aiohttp.ClientSession() as session:
        f1 = open(text_path, 'r')
        tar_path = store_path + '/'
        new_urls = [each_url.replace('\n', '') for each_url in f1.readlines()]
        # 文件命名我设置成下载链接的最后4位数字了,如果你有其他需求的,这里就可以做其他定制命名功能啦~
        task = [asyncio.create_task(pdfdownload(session, pdfurl=each_url, name=each_url[-8:-4], filespath=tar_path)) for each_url in new_urls]
        done, pending = await asyncio.wait(task)
        end_time = round(time.time() - s1, 2)
        mb = messagebox.showinfo(title='pdf批量下载器', message=f'全部下载完毕,共用时{end_time}秒。')

# 总控制函数,因为按钮的command不能调用上述的被async修饰过的函数,所以必须另起一个总控制函数进行调用。
def run_async():
    asyncio.run(start_download())

二、完整代码

完整代码会跟上面的顺序有点不一样,注意区别,你如果直接使用的话,那就直接使用完整代码即可。

# encoding = utf-8
# 使用异步下载方法测试速度
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import time
import asyncio  # 异步下载包也就是协程函数
import aiohttp

def save_file():
    global store_path
    store_path = filedialog.askdirectory()

# 创建下载函数
async def pdfdownload(session, pdfurl, name, filespath):
    # 因为你在下载的时候会遇到一些验证或者警告的提示,你可以使用verify_ssl=False语句进行强制不显示该警告
    async with session.get(pdfurl, verify_ssl=False) as re:
        with open(f'{filespath}' + f'{name}' + ".pdf", 'wb') as f1:
            while True:
                chunk = await re.content.read(1024)
                if not chunk:
                    break
                f1.write(chunk)

# 创建主窗口
root = tk.Tk()
root.title('PDF链接批量下载工具')
max_w, max_h = root.maxsize()
root.geometry(f'300x150+{int((max_w - 300) / 2)}+{int((max_h - 150) / 2)}')  # 居中显示
# 固定窗口尺寸不能修改
root.resizable(width=False, height=False)

# 创建输入窗
entry1 = tk.Entry(root)
entry1.place(relx=0.5, rely=0.5, width=100, anchor='center')


# 创建开始下载函数
async def start_download():
    s1 = time.time()
    async with aiohttp.ClientSession() as session:
        f1 = open(text_path, 'r')
        tar_path = store_path + '/'
        new_urls = [each_url.replace('\n', '') for each_url in f1.readlines()]
        task = [asyncio.create_task(pdfdownload(session, pdfurl=each_url, name=each_url[-8:-4], filespath=tar_path)) for each_url in new_urls]
        done, pending = await asyncio.wait(task)
        end_time = round(time.time() - s1, 2)
        mb = messagebox.showinfo(title='pdf批量下载器', message=f'全部下载完毕,共用时{end_time}秒。')


def run_async():
    asyncio.run(start_download())


# 创建打开文件函数
def openFile():
    global text_path
    text_path = filedialog.askopenfilename(filetypes=[('文本', '.txt')])
    # 关闭之前的窗口
    root.destroy()
    # 创建新窗口
    root1 = tk.Tk()
    max_w1, max_h1 = root1.maxsize()
    root1.geometry(f'+{int((max_w1 - 600) / 2)}+{int((max_h1 - 500) / 2)}')  # 居中显示
    # 创建scrollbar
    sb = tk.Scrollbar(root1)
    sb.grid(column=3, sticky='NS')
    # 创建text窗口
    text = tk.Text(root1, yscrollcommand=sb.set)  # yscrollcommand绑定sb的设置
    text.grid(row=0, column=0, columnspan=3)
    sb.config(command=text.yview)
    f = open(text_path, 'r', encoding='utf-8')
    text.insert('end', f.read())
    f.seek(0) # 光标移到开始位置
    # 文件个数
    global pdf_num
    pdf_num = len(f.readlines())
    # 创建标签
    lb = tk.Label(root1, text=f'总共有{pdf_num}个文件。')
    lb.grid(row=1, column=0)
    # 选择下载的位置
    button0 = tk.Button(root1, text='选择保存位置', command=save_file)
    button0.grid(row=1, column=1, pady=3)
    # 创建确认按钮
    button1 = tk.Button(root1, text='确认开始下载', width=10, command=run_async)
    button1.grid(row=1, column=2, pady=3)
    root1.mainloop()

# 选择文件标签
lab1 = tk.Label(root, text='选择文件:')
lab1.place(relx=0.35, rely=0.5, anchor='e')

# 创建获取文件路径按钮
b1 = tk.Button(root, text='获取文件', command=openFile)
b1.place(relx=0.7, rely=0.5, anchor='w')
tk.mainloop()

三、打包成exe文件

   python代码打包成exe执行文件的时候,一定要创建虚拟环境后再进行打包,不然你的exe执行文件将会大的无法想象,因为用Pyinstaller打包,将会将你安装过的所有包都一起打包,造成你的执行文件exe贼大。
我觉得怎么将python程序打包成exe文件的流程看这篇文章就够了:打包python程序
   希望大家都可以学得快乐, over~
exe文件自取:链接:https://pan.baidu.com/s/1RZJYqrTdWJnfzBwYNXSkCA
提取码:hikd
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Python Asyncio 是 Python 3.4 版本之后引入的一个标准库,它提供了一种异步编程的解决方案,使得 Python 开发者可以更加方便地实现高效的异步 IO 操作。相比于传统的多线程或多进程的方式,异步编程可以更好地利用 CPU 和 IO 资源,提高程序的运行效率。 以下是 Python Asyncio 的一些基本概念和用法: 1. 异步:异步指的是程序在执行 IO 操作时不会阻塞进程,而是在等待 IO 操作完成的同时可以执行其他任务。 2. 协程:协程是一种轻量级的线程,可以在一个线程中并发执行多个协程任务,从而实现异步编程。 3. 事件循环:事件循环是 Asyncio 中的核心概念,它负责调度协程任务的执行,以及处理 IO 事件。 4. Future:Future 是 Asyncio 中用于异步编程的一种对象,它表示一个异步操作的结果,可以用于等待异步操作的完成。 5. Task:Task 是 Future 的子类,表示一个协程任务,它封装了一个协程对象,并可以被事件循环调度执行。 以下是一个简单的使用 Asyncio 实现异步 IO 操作的例子: ```python import asyncio async def fetch_data(): print('Start fetching data...') await asyncio.sleep(1) # 模拟 IO 操作 print('Data fetched!') async def main(): task1 = asyncio.create_task(fetch_data()) task2 = asyncio.create_task(fetch_data()) await task1 await task2 asyncio.run(main()) ``` 在这个例子中,我们定义了一个 fetch_data 协程函数,它模拟了一个 IO 操作,并在操作完成后打印了一条消息。在 main 函数中,我们使用 asyncio.create_task 创建了两个任务,并等待它们的完成。由于这两个任务是并发执行的,所以它们的完成顺序是不确定的。 这只是 Asyncio 的一个简单示例,如果你想深入了解 Asyncio使用和原理,可以参考 Python 官方文档或者一些优秀的 Asyncio 教程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峰勇力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值