公众号文章剪藏工具制作GUI图形化界面


几十行代码为公众号文章剪藏工具制作GUI图形化界面,文末有彩蛋

图片

自从上次创建了我们的公众号剪藏脚本后,章鱼也在想以怎么样的方式能够让我们的小工具脚本能够让大家使用的更方便,经过一番折腾也遇到了不少的坑,终于实现了下面的功能,展示一个图形化的界面,在界面上直接粘贴链接实现公众号多篇文章图文下载。

不仅如此,章鱼还做了一个含有Pyhton内嵌环境的windows的绿色软件包,这样即使不会开发没有Python开发环境的小伙伴们使用这个小工具进行下载了。

GUI图文下载小工具

主要的功能:

这里章鱼用Python的一个简洁的图形库PySimpleGUI重新包装了公众号图文剪藏的小脚本,让它能够更简单的使用,它有以下功能:

  • 支持手动选择图文保存目录
  • 支持多篇文章批量下载,一篇文章一个换行
  • 多篇文章的添加了进度条
  • 进度和下载耗时内容打印
  • windows系统上免安装执行

工具界面:

临时地址

运行效果:

章鱼在windows 10 64位电脑上试了试效果是可以的

文章下载展示

一次下载的多篇文章:

下载文章

下载图文的预览效果:

image-20220424225945191

PySimpleGUI简单介绍

安装python依赖库

pip install pysimplegui
# 或是python3
pip3 install pysimplegui

一个简单案例:

image-20220424222224901
# 引入PySimpleGUI模块
import PySimpleGUI as sg

sg.theme('DarkAmber')  # 添加一个暗色主题
# 界面窗口中的组件
layout = [[sg.Text('Some text on Row 1')],
          [sg.Text('Enter something on Row 2'), sg.InputText()],
          [sg.Button('Ok'), sg.Button('Cancel')]]

# 创建窗口,填入layout界面布局
window = sg.Window('Window Title', layout)
# 监听窗口事件和输入
while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == 'Cancel':  # if user closes window or clicks cancel
        break
    print('You entered ', values[0])

window.close()

我们再开发工具PyCharm创建一个python文件,把代码拷贝过去执行,可以看到弹窗就出现了

image-20220424222133305

定义组件:

这里面主要是界面布局layout的组件

组件名 对象 作用
文本组件 sg.Text() 展示文本内容
输入框 sg.InputText() 接受用户输入的键盘文字
按钮 sg.Button() 用户可以点击,不同的按钮可以产生不同的时间
主题 sg.theme() 窗口的颜色样式主题,有固定的值可以参考文档
窗口 sg.Window(‘Window Title’, layout) 用来承载组件,展示和接受事件响应

案例中layout布局是一个组件的数组,它定义了一个嵌套数组,外层数组的每一个值是都是界面中的一行元素,每一行的组件又是一个数组,每行的数组里面可以添加多个组件

layout = [[sg.Text('Some text on Row 1')],
          [sg.Text('Enter something on Row 2'), sg.InputText()],
          [sg.Button('Ok'), sg.Button('Cancel')]]
  • layout的第一个数组元素:[sg.Text('Some text on Row 1')] 是一个数组里面定义了文本组件
  • layout的第二个数组元素[sg.Text('Enter something on Row 2'), sg.InputText()],定义了两个组件一个文本展示,一个文本输入框
  • layout的第三个数组元素 [sg.Button('Ok'), sg.Button('Cancel')],定义了两个按钮,一个ok、一个cancel

整个组件定义是按从上到下的流式布局的,展示也是从上到下的展示窗口组件

组件事件侦听和处理:

在定义完成组件和创建window窗口对象后window = sg.Window('Window Title', layout)

程序定义了一个while循环语句,不能断的通过window.read()读取窗口的信息

window.read()方法会返回两个值,一个是当前事件名称event,一个是读取的窗口的数组值values

# 监听窗口事件和输入
while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == 'Cancel':  # if user closes window or clicks cancel
        break
    print('You entered ', values[0])

用户在界面上的操作,如关闭窗口、点击Cancel取消按钮,都会出发event事件,事件返回对应的按钮名称

这里可以做逻辑处理,点击按钮执行一段逻辑处理等。

详细的案例可以看PySimpleGUI官网手册,和PySimpleGUI GitHub仓库地址的介绍,里面有很多现成案例,而且直接就能跑起来,喜欢进一步了解的小伙伴可以参考官方的例子,比如下面的路径:

Github上下载PySimpleGUI的master分支文件,本地解压关注一下目录:

image-20220424221229836

章鱼的这个小工具的界面设计,就是从其中先有的Demo布局中拿来就用的,改改内容,有问题的再查查资料

image-20220424220948298

代码实现GUI工具

这里把上篇文章用Python实现公众号文章原汁原味剪藏的剪藏脚本封装了一个download方法,并返回下载的文章名称信息

1. 剪藏工具的GUI布局

主要包含五块内容:

  1. 保存目录
  2. 文章链接
  3. 进度条
  4. 输出框
  5. 运行和退出按钮
image-20220424230653812
# 设置组件和布局
layout = [
    [sg.Text('保存目录'), sg.InputText(size=(45, 1), key='-FOLDER-'), sg.FolderBrowse()],
    [sg.Frame('微信文章链接', font='Any 10', layout=[
        [sg.ML(size=(65, 5), enter_submits=False, key='textarea', do_not_clear=True)]])],
    [sg.Frame('进度', font='Any 10', layout=[[sg.ProgressBar(1, orientation="h", size=(45, 15), key="progressbar")]])],
    [sg.Frame('输出', font='Any 10', layout=[
        [sg.Output(size=(65, 15), font='Courier 10')]])],
    [sg.Button('运行', key='Run', bind_return_key=True),
     sg.Button('退出', key='Quit', button_color=('white', 'firebrick3'))],
    [sg.Text('Made by 章鱼 公众号:章鱼的学习探索 ', auto_size_text=True, font='Courier 8')]]

# 设置窗口标题
window = sg.Window('微信文章下载小工具', layout, auto_size_text=False, auto_size_buttons=False,
                   default_element_size=(20, 1), text_justification='right')

主要涉及到的组件如下:

组件名 对象 作用
文本组件 sg.Text() 展示文本内容
输入框 sg.InputText(size=(45, 1), key=’-FOLDER-‘) 定义key值-FOLDER-接受文件夹选择框的值
文件浏览框 sg.FolderBrowse() 浏览文件夹,类似的有文件选择器
进度条 sg.ProgressBar() 展示进度
输出框 sg.Output() 打印控制台print()方法的输出

2. GUI界面的事件处理

主要是针对界面组件事件进行处理

主要处理的事件:

  1. ‘Exit’, ‘Quit’ 退出和关闭事件
  2. ‘Run’事件,sg.Button('运行', key='Run', bind_return_key=True)按钮所绑定的事件

3. 界面下载的主流程

所以当点击’运行’按钮会出发Run事件,接下来就会走处理流程

  • 从valuse值字典获取key为-FOLDER-的文件夹浏览框的值
  • 从window对象获取key为progressbar的进度条对象
  • 从valuse值字典获取key为textarea的文章链接的文本框的值
  • 文本框和文件框为空的话提示弹窗,结束当前循环
  • 从文本框中获取文章多行链接进行分行处理,遍历执行downloadUtil.download(article_url, folder)的下载方法,下载多篇文章
  • 异常情况捕获异常并打印输出

代码如下:

while True:
    event, values = window.read()
    if event in ('Exit', 'Quit', None):
        break
    # 设置进度条的最大值
    progress_bar = window["progressbar"]
    # 获取保存目录
    folder = values['-FOLDER-']
    # UI事件处理
    if event == 'Run':
        try:
            print("folder:", folder)
            textarea = values['textarea']
            if not folder:
                sg.popup("提示", "保存文件地址不能为空!")
                continue
            if not textarea:
                sg.popup('提示', "下载地址不能为空!请填写下载的地址,多个换行")
                continue
            startime = datetime.datetime.now()
            print(type(textarea))
            lines = textarea.splitlines()
            print(f'总文章数:{len(lines)}')
            print("保存地址:", folder)
            print('开始执行文章下载处理...程序启动中...')
            for index in range(0,len(lines)):
                line = lines[index]
                article_url = line.strip()
                # print(f"文章_{index + 1}:{article_url}")
                article_filename = downloadUtil.download(article_url, folder)
                print(f"文章_{index + 1} 标题:{article_filename} 下载完成")
                progress_bar.update_bar(index + 1, len(lines))
                window.Refresh()
            # 结束时间
            endtime = datetime.datetime.now()
            time_long = endtime - startime
            print("流程耗时:", time_long)
            print('**** DONE ****')
        except Exception as e:
            sg.PopupError('发生了点错误',
                          'close this window and copy command line from text printed out in main window',
                          'Here is the output from the run', e.args)
            print('程序执行发生了些错误:\n\n', e.args)
            print(str(e))

图形界面的GUI的全部代码:

# !/usr/bin/env python
import PySimpleGUI as sg
import os
import datetime
import download_util as downloadUtil

sg.theme('LightGreen')
# 设置组件和布局
layout = [
    [sg.Text('保存目录'), sg.InputText(size=(45, 1), key='-FOLDER-'), sg.FolderBrowse()],
    [sg.Frame('微信文章链接', font='Any 10', layout=[
        [sg.ML(size=(65, 5), enter_submits=False, key='textarea', do_not_clear=True)]])],
    [sg.Frame('进度', font='Any 10', layout=[[sg.ProgressBar(1, orientation="h", size=(45, 15), key="progressbar")]])],
    [sg.Frame('输出', font='Any 10', layout=[
        [sg.Output(size=(65, 15), font='Courier 10')]])],
    [sg.Button('运行', key='Run', bind_return_key=True),
     sg.Button('退出', key='Quit', button_color=('white', 'firebrick3'))],
    [sg.Text('Made by 章鱼 公众号:章鱼的学习探索 ', auto_size_text=True, font='Courier 8')]]

# 设置窗口标题
window = sg.Window('微信文章下载小工具', layout, auto_size_text=False, auto_size_buttons=False,
                   default_element_size=(20, 1), text_justification='right')

# ---===--- Loop taking in user input --- #
while True:
    event, values = window.read()
    if event in ('Exit', 'Quit', None):
        break
    # 设置进度条的最大值
    progress_bar = window["progressbar"]
    # 获取保存目录
    folder = values['-FOLDER-']
    # UI事件处理
    if event == 'Run':
        try:
            print("folder:", folder)
            textarea = values['textarea']
            if not folder:
                sg.popup("提示", "保存文件地址不能为空!")
                continue
            if not textarea:
                sg.popup('提示', "下载地址不能为空!请填写下载的地址,多个换行")
                continue
            startime = datetime.datetime.now()
            print(type(textarea))
            lines = textarea.splitlines()
            print(f'总文章数:{len(lines)}')
            print("保存地址:", folder)
            print('开始执行文章下载处理...程序启动中...')
            for index in range(0,len(lines)):
                line = lines[index]
                article_url = line.strip()
                # print(f"文章_{index + 1}:{article_url}")
                article_filename = downloadUtil.download(article_url, folder)
                print(f"文章_{index + 1} 标题:{article_filename} 下载完成")
                progress_bar.update_bar(index + 1, len(lines))
                window.Refresh()
            # 结束时间
            endtime = datetime.datetime.now()
            time_long = endtime - startime
            print("流程耗时:", time_long)
            print('**** DONE ****')
        except Exception as e:
            sg.PopupError('发生了点错误',
                          'close this window and copy command line from text printed out in main window',
                          'Here is the output from the run', e.args)
            print('程序执行发生了些错误:\n\n', e.args)
            print(str(e))

封装工具的代码:

download_util.py脚本中新增下面的封装方法,传入文章链接article_url和文章存储目录save_folder

走之前异步下载的流程方式下载文章图文,方法最终返回return article_filename当前下载文章名,文章名用在GUI的输出框,可以看当前下载的文章地址。

下载相关的核心流程看上一篇文章

def download(article_url, save_folder):
    """
    定义下载入口
    :param article_url: 文章链接
    :param save_folder: 保存文件夹路径
    :return:
    """
    start = time.time()
    # 当前时间戳,用来做文件名前缀
    base_picprefix = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
    # 存储路径信息
    # base_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), save_folder)
    base_path = save_folder
    if not os.path.exists(base_path):
        os.makedirs(base_path)

    # 更新headers的地方

    # 异步循环处理
    loop = asyncio.get_event_loop()
    task = loop.create_task(get_html(article_url, base_path, base_picprefix))
    # 🉑️第一个获取文章task返回的信息,图片列表,网页的html文本,文章作者信息,处理后的文章标题
    links, html, article_info, article_filename = loop.run_until_complete(task)
    # 新的异步任务列,用来下载图片
    tasks = []
    old_new_links_dicts = []
    # 构造图片存储文件名
    index = 0
    for link in links:
        pic_name = base_picprefix + "_" + str(index)
        tasks.append(download_picfile(link, base_path, pic_name, old_new_links_dicts))
        index += 1
    # 头图下载保存到html文件同路径,不记录到替换列表中
    tasks.append(download_picfile(link, base_path, article_filename, None, ''))
    # 批量执行并等待结果
    loop.run_until_complete(asyncio.gather(*tasks))
    # print("替换列表:", old_new_links_dicts)
    # 执行完批量处理后,处理html的文本内容
    update_htmlfile_imgs(base_path, article_filename, old_new_links_dicts)
    end = time.time()
    print(f'下载完成{index}个图片,用时:{end - start}秒')
    return article_filename

小结

本次给大家介绍了如何使用PySimpleGUI库给Python脚本添加图形化界面的流程,并介绍了PySimpleGUI的小例子,希望能给大家一些启发。

思考题:

  1. 需求是不断提升的,本次实现了多个公众号文章链接批量下载,那如果要下载的是否能够改进一下实现一个读取表格文件的的批量下载呢
  2. 本文的程序还有不足虽然图片能够下载本地,但是一些资源仍依赖公网,断网后可能无法正常展示,比如文章的样式居中展示和代码行样式,所以能否保存网页为PDF一类的格式文档呢,这样脱离了网络环境依然能够展示,虽然网页的可以展示Gif动图一类的,但是对于重要的阅读文本居多

答案是有的,PDF这块章鱼已经测试过了可以使用wkhtmltopdf来保存图文,样式也不会失真,下期文章会分享一下

公众粉丝福利:

本篇文章的图形GUI版本的剪藏小工具绿色版为公众号粉丝免费提供,不用写代码也可以使用工具。

章鱼通过探索把代码打包成绿色包,里面包含这次的源代码和Pyhton执行环境,可以在windows系统正常运行,Mac端打包比较麻烦苹果电脑暂时不支持。

包的内容不大,压缩后不到30MB

微信图文下载工具大小

使用方式

解压后双击启动脚本.vbe执行,会启动GUI程序

另外:源码也在这个压缩包里面,相信大家看到了download_util.py,就是这个python脚本文件

run.bat也能执行GUI,但是会带一个命令行窗口影响使用,建议使用启动脚本

PS:程序使用的是python的embed内嵌包,无毒副作用请放心使用

执行方式

获取方式

章鱼的学习探索公众号,回复:220425

长按识别二维码关注:

qrcode_for_gh_a7455fb62844_344

欢迎点赞、留言和转发~


文章作者: 章鱼的学习探索
版权声明: 本站点所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 章鱼的学习探索 !
  目录