分类目录归档:生活智能化

Easyocr — 3行代码识别图片中的任意语言文字

今天给大家介绍一个超级简单且强大的OCR文本识别工具:easyocr.

这个模块支持70多种语言的即用型OCR,包括中文,日文,韩文和泰文等。

下面是使用这个模块的实战教程。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install easyocr

它会安装除了模型文件之外的所有依赖,模型文件则会在运行代码的时候下载。

对于Windows,如果在安装Torch或Torchvision时报错了,请先按照https://pytorch.org的官方说明安装Torch和Torchvision 。

在pytorch网站上,请确保选择正确的CUDA版本。如果仅打算在CPU模式下运行,请选择CUDA = None。

2.实战教程

这个模块用起来真的非常简单,三行代码完事了:

import easyocr
reader = easyocr.Reader(['ch_sim','en'])
result = reader.readtext('test.png')

运行的过程中会安装所需要的模型文件,像下面这样:

不过它的下载速度非常慢,而且经常会失败,因此这里给出第二个解决方案:先下载好模型文件,再将其放置到所需要的位置:

如果下载速度太慢,请在Python实用宝典公众号后台回复:easyocr, 下载我上传到微云网盘的文字检测模型(CRAFT)和中文简体模型文件包。

下载完模型后,将文件放到下面这个位置。

Windows:C:\Users\用户名.EasyOCR\model
Linux:~/ .EasyOCR / model

重新执行脚本不会再提醒下载模型了:

import easyocr
reader = easyocr.Reader(['ch_sim'])
result = reader.readtext('test.png')
print(result)

我随便截了一个直播弹幕的图片保存在脚本所在的文件夹下,命名为test.png:

结果如下:

基本上所有应该识别的文字都识别出来了,效果非常不错。

另外也可以看到,输出采用列表格式,每个item分别表示对应文字的边界框,识别文本结果和置信度。

这个模块还能识别多语种的情况:

我将这张图片命名为test2.jpg,修改代码中对应的图片名称:

import easyocr
reader = easyocr.Reader(['ch_sim','en'])
result = reader.readtext('test2.jpg')
print(result)

效果如下:

这张图片很复杂,而且是中英文混杂在一起的情况,但是可以看到模型除了左上角的水印,图片中的文字基本都是识别出来了,尽管有部分文字识别错误,但还在可以接受的范围之内。

不过需要注意的是,虽然可以一次性识别许多种语言,但并非所有语言都可以一起用,通常是公共语言和一个特殊语种可以一起识别,相互兼容,比如英语和日语。

如果你的电脑没有GPU或者显存不足,可以加一个gpu=false的参数仅使用CPU运行:

reader = easyocr.Reader(['ch_sim','en'], gpu = False)

另外,这个模块还支持直接使用命令行运行,相当方便,大家可以试一试:

easyocr -l ch_sim en -f test.png --detail=1 --gpu=True

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

一行代码将任何Python 程序转换为图形界面(GUI)应用程序

Gooey项目支持用一行代码将(几乎)任何Python 2或3控制台程序转换为GUI应用程序。

1.快速开始

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

安装说明

(方式一)安装Gooey的最简单方法是通过 pip

pip install Gooey 

(方式二)或者,您可以通过将项目克隆到本地目录来安装Gooey

git clone https://github.com/chriskiehl/Gooey.git

如果你的网络不支持从GitHub克隆,请在Python实用宝典上回复:Gooey 下载项目源代码。

解压后进入该文件夹,运行 setup.py:

python setup.py install

2.使用方法

Gooey 通过将一个简单的装饰器附加到主函数上,然后使用GooeyParser可将你所有需要用到的参数可视化为文本框、选择框甚至是文件选择框。

比如在scihub文献下载的文章中,我们需要输入两个参数:1.关键词,2.下载篇数,使用Gooey可以这么改:

from gooey import Gooey, GooeyParser

@Gooey
def main():
    parser = GooeyParser(description="中文环境可用的scihub下载器 - @Python实用宝典") 
    parser.add_argument('path', help="下载路径", widget="DirChooser")
    parser.add_argument('keywords', help="关键词")
    parser.add_argument('limit', help="下载篇数")
    args = parser.parse_args()
    search(args.keywords, int(args.limit), args.path)

GooeyParser 和 ArgumentParser 一样,使用 add_argument 就可以增加输入参数,不同的是 GooeyParser 提供了可视化的选项:

parser.add_argument('path', help="下载路径", widget="DirChooser")

这一行代码,widget 参数给 args.path 变量提供了一个目录选择器(widget=”DirChooser”),help参数用于提醒用户该选择器的作用,效果如下:

当你不提供widget参数时,程序默认使用文本输入框。

parser.add_argument('keywords', help="关键词")
parser.add_argument('limit', help="下载篇数")

Gooey会自动编排你的参数,因此你不需要担心各个文本框或选择框的显示问题。

args = parser.parse_args()
search(args.keywords, int(args.limit), args.path)

args = parser.parse_args() 可以将用户输入的所有文本转化为对应对象的变量值,通过 args.var 可以直接提取对应的变量值。

这个简单的可视化程序完整代码及效果如下:

import asyncio
from scihub import SciHub
from gooey import Gooey, GooeyParser

def search(keywords: str, limit: int, path: str):
    """
    搜索相关论文并下载

    Args:
        keywords (str): 关键词
        limit (int): 篇数
        path (str): 下载路径
    """
    sh = SciHub()
    result = sh.search(keywords, limit=limit)
    print(result)

    loop = asyncio.get_event_loop()
    # 获取所有需要下载的scihub直链
    tasks = [sh.async_get_direct_url(paper["url"]) for paper in result.get("papers", [])]
    all_direct_urls = loop.run_until_complete(asyncio.gather(*tasks))
    print(all_direct_urls)

    # 下载所有论文
    loop.run_until_complete(sh.async_download(loop, all_direct_urls, path=path))
    loop.close()

@Gooey
def main():
    parser = GooeyParser(description="中文环境可用的scihub下载器 - @Python实用宝典") 
    parser.add_argument('path', help="下载路径", widget="DirChooser")
    parser.add_argument('keywords', help="关键词")
    parser.add_argument('limit', help="下载篇数")
    args = parser.parse_args()
    search(args.keywords, int(args.limit), args.path)

main()

这份代码想要完美地运行起来请结合 你不得不知道的python超级文献批量搜索下载工具 的 scihub.py.

你也完全可以使用自己的程序进行图形界面化,这无关紧要。

效果如下:

3.支持的widget组件

所有支持的widget组件如下:

1.勾选框 widget=”CheckBox”

2.下拉框 widget=”DropDown”

3.互斥选择框 widget=”RadioGroup”

4.各种目标类型的选择框

文件选择框 widget=”FileChooser”
目录选择框 widget=”DirChooser”
多文件选择框 widget=”MultiFileChooser”
文件保存目录 widget=”FileSaver”

5.日期/时间选择器 widget=”DateChooser/TimeChooser”

6.密码输入框 wiget=”PasswordField”

7.多选列表框 widget=”Listbox”

8.颜色选择器 widget=”ColourChooser”

9.可过滤的下拉框 widget=”FilterableDropdown”

10.滑片 widget=”Slider”

4.打包

在一切都测试完毕后使用正常后,你可以通过 pyinstaller 将这个可视化程序打包成exe可执行文件。

1.编写 PyInstaller buildspec

PyInstaller使用 buildspec 来确定如何捆绑项目。你可以在Python实用宝典后台回复 buildspec下载 build.spec.txt.

下载后你只需要改两行代码:

如下所示:

在路径前面带r,可以不用输入两个斜杆 ‘\’ 哦。

2.执行打包命令

为了能够使用 PyInstaller, 我们需要使用pip安装这个模块:

pip install pyinstaller

然后进入 build.spec.text 所在文件夹,执行以下命令打包程序:

pyinstaller build.spec

打包完成后会在当前文件夹下生成一个dist文件夹,里面就包含了你打包生成的可执行文件。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

马赛克还原神器—Depix,真的有那么神吗?

Depix 是用于从马赛克中还原密码/英文数字组合的Python工具。

它的官方效果是这样的:

效果非常令人惊艳,恢复后基本和原文图相差无几。但是真的有那么神吗?

1.怎么做到的?

第一步,作者在编辑器中使用了与原图(带有马赛克的图片)相同的字体设置(文本大小,字体,颜色等设置),然后将 debruinseq.txt 内的文字和数字放入编辑器中并截图,这张截图中的所有文字都将被像素化后作为“搜索集”来识别原图中马赛克的真实内容。

第二步,将原图中的马赛克方块切出来成为一个个单个矩形,然后这些矩形将与“搜索集”中的每个块进行比对,找到最正确的结果。

第三步,在对应位置上对搜索集和原图中周围方块的匹配进行几何比较找到最短距离,重复此过程几次,找到最优结果。

接下来,让咱们试试这个Depix,看看是不是真的那么神。

2. 安装依赖

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

为了使用该项目的源代码,请前往GitHub下载:
https://github.com/beurtschipper/Depix

如果你访问不了GitHub或网速过慢,可以在Python实用宝典公众号后台回复:depix 下载。

解压下载好的文件得到 Depix-main 文件夹,Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),cd 进入 Depix-main 文件夹,输入命令安装依赖:

pip install -r requirements.txt

3.试一试

首先试一下作者的示例,在Depix-main文件夹下运行以下命令,采用作者的打码图作为识别的目标对象:

images/testimages/testimage3_pixels.png

使用作者生成好的图片作为“搜索集”:

images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png

运行以下命令开始识别:

python depix.py -p images/testimages/testimage3_pixels.png -s images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png -o output.png

识别结束后会在当前文件夹生成 output.png

效果还不错,但这是作者提供的图片,如果是我们自己的图片呢?

比如我在编辑器中键入这样的文字再打码,它能识别到吗:

打码:

使用作者的“搜索集”来解码:

python depix.py -p G:\push\20210114\test.png -s images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png -o output.png

结果出来的图基本和打码图没什么变化,基本无效果。

我以为是“搜索集”的问题,比如字体不一样导致无法识别成功。

因此我学作者制作了一个“搜索集”:

然后使用这个搜索集再进行识别:

python depix.py -p G:\push\20210114\test.png -s G:\push\20210114\train1.png -o output.png

依然没有识别成功,出来的结果还是和原图差不多,马赛克基本没少。

后面又试了几次,均没有识别成功。

5.为什么我的马赛克无法被识别

于是我想知道为什么会这样,就用我自己的马赛克工具和作者打的马赛克做了对比:

我发现,使用我的马赛克图像去进行识别的时候,一样没有任何效果

但是识别作者的马赛克图像,效果却很好。

这时候我有理由相信这个算法其实发生了“过拟合”,作者对“搜索集”的每个区块进行打码,这个打码的风格是有一定特征的,如果被识别对象的马赛克不符合这个风格,那识别大概率会失败。

所以被识别对象的马赛克一定要符合“搜索集”的打码风格,这样才能被准确地识别出来,换成其他算法生成的马赛克,作者的模型都可能会失效,就比如我刚刚试的那些例子。

尽管如此,随着技术的进步,在未来类似这样的解码器肯定会越来越强大,所以建议大家还是将马赛克打得厚一点,最好是一整块地填充图像破坏原图,这样才不用担心密码被还原之类的事情,比如下面这样才是最安全的。

最后一个问题,这两个被覆盖掉的字是什么?(狗头保命​

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

You-get 万能的音视频下载工具

You-Get 是一个使用Python开发的小型命令行实用程序,可以通过一行命令直接从Web下载媒体内容(视频,音频,图像)等,不用任何配置。

这款工具支持的站点特别多,比如Youtube、优酷、腾讯视频、网易云音乐、Ted、知乎等等主流网站,可以说几乎是万能的,在本文最下方的附录可查看You-Get支持的完整网站列表。

下面是这个万能工具的使用指南。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install you-get

2.使用方法

使用的时候直接在命令行输入:

you-get 媒体链接

就能将媒体内容下载在当前命令行输出的文件夹中,比如下载网易云音乐的歌曲:
https://music.163.com/#/song?id=1811118551

不仅如此,下载B站的视频,它连多part视频都能一并下载:

第一次下载的时候,它会提示这是个多part视频,后缀添加–playlist下载全部part视频:

令人惊喜的是,这个工具在下载视频的同时将弹幕数据也下载了:

弹幕文件通过 danmu2ass 这样的工具处理后,就可以将弹幕数据格式化为ass文件,用播放器播放视频的时候,将ass格式的弹幕文件导入到播放器,就能完美复现B站的体验效果。

知乎的下载比较特别,只支持下载回答和专栏内出现的视频:

3.增值功能

3.1 暂停和继续下载

没错,这个工具支持断点续传,这是为了防止出现下载的视频太长,用户中途停止导致前面下载的内容报废的问题。

1.暂停下载:按 Ctrl+C 可以中断命令,下载目录下会保存有一个以 .download 为扩展名的缓存文件。

2.继续下载:重新执行相同的命令下载任务,如果下载目录下有上次下载保存的缓存文件,则继续上次下载进度。

3.强制重新下载(即使下载完成也会重新写入),带 -f 参数即可:

you-get -f https://www.bilibili.com/video/BV137411n7hY

3.2 选择视频格式和清晰度

用过 -i 参数能获得当前视频所有的清晰度和格式:

拿到格式名称后,如果你想下载高清 1080P的视频,只需要带–format参数就可以下载指定格式的视频:

you-get --format=dash-flv https://www.bilibili.com/video/BV137411n7hY

3.3 本地播放器直接播放网络视频

这也是一个相当强力的特性,如果你受不了网页播放器那些简单的功能,想加一些比如调整屏幕比例为2.35:1之类的自己本地播放器的功能,那你可以尝试这样做:

1.在资源管理器中打开 你的播放器的 安装目录
2.按住Shift并在空白处右击鼠标,选择在此处打开 Powershell 窗口
3.输入下面的 You-Get 播放命令即可

you-get -p 你的播放器.exe https://www.bilibili.com/video/BV1Fa4y1a7jE

3.4 代理设置

你如果有下载油管之类的视频的需求,那么可能需要设置代理才可以下载成功,you-get 也提供了这样的选项:

you-get -x 127.0.0.1:8087 'https://www.youtube.com/watch?v=jNQXAC9IVRw'

-x 参数后接代理的 IP:端口号,再将需要下载的视频链接放到后面就可以了,非常方便。

3.5 设置下载文件的路径

如果你不想把文件下载到当前命令行所处的文件夹中,那么可以用 -o 参数指定下载目录:

you-get -o C:\Users\83493\Downloads 'https://www.bilibili.com/video/BV1Fa4y1a7jE'

大体功能就是这些,相信已经能够覆盖大家的日常使用范围了,喜欢的话请在下方点个赞或者在看让更多的人看到吧!

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

附录:

SiteURL视频图像音频
YouTubehttps://www.youtube.com/
Twitterhttps://twitter.com/
VKhttp://vk.com/
Vinehttps://vine.co/
Vimeohttps://vimeo.com/
Veohhttp://www.veoh.com/
Tumblrhttps://www.tumblr.com/
TEDhttp://www.ted.com/
SoundCloudhttps://soundcloud.com/
SHOWROOMhttps://www.showroom-live.com/
Pinteresthttps://www.pinterest.com/
MTV81http://www.mtv81.com/
Mixcloudhttps://www.mixcloud.com/
Metacafehttp://www.metacafe.com/
Magistohttp://www.magisto.com/
Khan Academyhttps://www.khanacademy.org/
Internet Archivehttps://archive.org/
Instagramhttps://instagram.com/
InfoQhttp://www.infoq.com/presentations/
Imgurhttp://imgur.com/
Heavy Music Archivehttp://www.heavy-music.ru/
Freesoundhttp://www.freesound.org/
Flickrhttps://www.flickr.com/
FC2 Videohttp://video.fc2.com/
Facebookhttps://www.facebook.com/
eHowhttp://www.ehow.com/
Dailymotionhttp://www.dailymotion.com/
Coubhttp://coub.com/
CBShttp://www.cbs.com/
Bandcamphttp://bandcamp.com/
AliveThaihttp://alive.in.th/
interest.mehttp://ch.interest.me/tvn
755
ナナゴーゴー
http://7gogo.jp/
niconico
ニコニコ動画
http://www.nicovideo.jp/
163
网易视频
网易云音乐
http://v.163.com/
http://music.163.com/
56网http://www.56.com/
AcFunhttp://www.acfun.cn/
Baidu
百度贴吧
http://tieba.baidu.com/
爆米花网http://www.baomihua.com/
bilibili
哔哩哔哩
http://www.bilibili.com/
豆瓣http://www.douban.com/
斗鱼http://www.douyutv.com/
凤凰视频http://v.ifeng.com/
风行网http://www.fun.tv/
iQIYI
爱奇艺
http://www.iqiyi.com/
激动网http://www.joy.cn/
酷6网http://www.ku6.com/
酷狗音乐http://www.kugou.com/
酷我音乐http://www.kuwo.cn/
乐视网http://www.le.com/
荔枝FMhttp://www.lizhi.fm/
懒人听书http://www.lrts.me/
秒拍http://www.miaopai.com/
MioMio弹幕网http://www.miomio.tv/
MissEvan
猫耳FM
http://www.missevan.com/
痞客邦https://www.pixnet.net/
PPTV聚力http://www.pptv.com/
齐鲁网http://v.iqilu.com/
QQ
腾讯视频
http://v.qq.com/
企鹅直播http://live.qq.com/
Sina
新浪视频
微博秒拍视频
http://video.sina.com.cn/
http://video.weibo.com/
Sohu
搜狐视频
http://tv.sohu.com/
Tudou
土豆
http://www.tudou.com/
阳光卫视http://www.isuntv.com/
Youku
优酷
http://www.youku.com/
战旗TVhttp://www.zhanqi.tv/lives
央视网http://www.cntv.cn/
Naver
네이버
http://tvcast.naver.com/
芒果TVhttp://www.mgtv.com/
火猫TVhttp://www.huomao.com/
阳光宽频网http://www.365yg.com/
西瓜视频https://www.ixigua.com/
新片场https://www.xinpianchang.com/
快手https://www.kuaishou.com/
抖音https://www.douyin.com/
TikTokhttps://www.tiktok.com/
中国体育(TV)http://v.zhibo.tv/
http://video.zhibo.tv/
知乎https://www.zhihu.com/

jinja2+yagmail 批量定制化渲染发送元旦祝福邮件

上一篇关于邮件的自动发送教程中,我们讲解了如何使用yagmail进行简单的邮件发送。

现实生活中,如果只是发邮件给自己,像上一篇文章那样简陋的格式是可以接受的,但若要针对每个人进行邮件的定制化,群发给公司客户、内部员工、亲戚朋友,则需更加高级的邮件发送方式。

我们可以通过HTML制作一封精美的元旦祝福邮件,但是邮件的内容——比如姓名、祝福语等应该怎样动态渲染呢?答案是jinja2.

jinja2 是一个Python 的模板引擎,使用jinja2,我们能够在邮件HTML中设定占位符,在Python发送邮件的时候,将指定文本渲染到该占位符中,实现动态渲染的目的。

比如举一个jinja2的简单例子:

from jinja2 import Template

name = 'Peter'
age = 34

tm = Template("My name is {{ name }} and I am {{ age }}")
msg = tm.render(name=name, age=age)

print(msg)

使用 {{}} 圈起来的是占位符,称之为模板字符串。模板字符串呈现两个变量:名称和年龄,在这个例子中,硬编码了name和age的值传入模板,得到输出:

My name is Peter and I am 34

在本篇文章中,我将教大家如何通过Html及Python+jinja2给你的好友们定制元旦祝福邮件。

本文所有素材及源代码均可以在此下载:
https://pythondict.com/download/python-new-year-mail/

或Python实用宝典公众号回复:元旦邮件 直接拿到网盘下载链接。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

此外,推荐大家用VSCode编辑器,因为它实在是太方便了:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),准备开始输入命令安装依赖。

pip install jinja2
pip install yagmail

2.编写HTML

将需要发送的邮件模板的HTML编写好。并将占位符变量提前写入HTML中。由于我的HTML文件过大,这里就不完全展示了,只展示几个关键变量。

为简化教程的复杂度,并尽可能覆盖到知识点,这里我们使用4个变量:

1.LOGO图片(让你更好地理解图片是如何渲染到HTMl里并发邮件)
2.背景图片
3.祝福对象
4.祝福语言

首先,是图片变量的配置:

<tr>
    <td valign="left" width="50%" class="logo sub-gd" style="padding-left:0;">
        <h1>
            <img src="data:image/png;base64, {{pythondict_img}}">
        </h1>
    </td>
</tr>

由于我们需要发送html形的邮件,因此像代码这样将图片转码为base64再发送是最方便的。

其中,base64部分用jinja2语法 {{}} 包起来,中间就是变量名,一会render渲染的时候就会将base64渲染进来。

背景图片的配置比较特殊,使用 base64 渲染的话QQ邮箱会自动过滤为#号,因此必须使用url的形式:

<td valign="middle"style="background-image: url({{backgroud}});">

其次是祝福对象和祝福语言的配置:

<h2>
    {{name}}
    <br>
    祝您2021年元旦快乐
</h2>
<p>
    {{bless}}.
</p>

使用 {{}} 包裹变量,name是祝福的对象,bless是祝福语。这里简化了代码,还有许多样式要配置详细的大家可以看源代码中的 index_detail.html.

对了,我们源代码里包括两份html,一份是 index_detail.html 是未经过压缩的源代码,还有一份是 index.html,是被压缩过的源代码。

为什么要压缩HTML呢?因为邮箱客户端在解析HTML的时候,有可能会将换行符解析成<br>,因此压缩HTML不保留任何空格和换行符是最保险的做法。

详细的HTML代码,大家可以看源代码中的 index_detail.html.

3.Python代码

发送邮件的方法,我们在Python 自动发送邮件详细教程中已经详细地讲过了:

class Mail:
    """
    邮件相关类
    """

    def log(self, content):
        now_time = time.strftime(
            "%Y-%m-%d %H:%M:%S", time.localtime()
        )
        print(f'{now_time}: {content}')

    def sendmail(self, html, title, receivers):
        """
        发送邮件
        Arguments:
            html {str} -- 邮件正文(html)
            title {str} -- 邮件标题
            receivers {list} -- 邮件接收者,数组
        """

        yag = yagmail.SMTP(
            host='您的邮箱SMTPHOST', user='您的邮箱',
            password='您的邮箱密码', smtp_ssl=True
        )

        yag.send(receivers, title, html)
        self.log("邮件发送成功")

此外,为了渲染图片,需要将图片转化为base64,这个方法是这样的:

def get_image_base64(path):
    """
    获得图片的base64编码

    Args:
        path (str): 图片路径

    Returns:
        str: base64编码
    """
    import base64
    f = open(path, "rb")
    base64_data = base64.b64encode(f.read())
    f.close()
    return base64_data.decode("utf-8")

当然,最重要的地方是下面,需要针对每个人定制祝福语,我们可以采用字典的数据结构来保存数据:

bless_info = {
    "admin@pythondict.com": {
        "pythondict_img": get_image_base64("./images/pythondict.png"),
        "name": "实用宝典",
        "background": "https://背景图片.jpg",
        "bless": "愿所有的幸运与您不期而遇..",
        "title": "祝宝典哥明年粉丝破十万"
    },
    "test@qq.com": {
        "pythondict_img": get_image_base64("./images/pythondict.png"),
        "name": "老王",
        "background": "https://背景图片.jpg",
        "bless": "祝您女儿明年考研顺顺利利,全家幸福安康..",
        "title": "老王,祝您元旦快乐!"
    },
}

可以看到 bless_info 字典里的每个key是发送对象的邮箱,而这些 key 对应的value 中就有需要渲染到邮件的变量: pythondict_img, name, background 及 祝福语bless. 最后一个变量title,是用于指定邮件标题的。

这样,渲染+发送邮件做起来就方便多了:

tm = Template(open('./index.html', encoding="utf-8").read())
for mail in bless_info:
    msg = tm.render(bless_info[mail])
    Mail().sendmail(html=msg, title=bless_info[mail]["title"], receivers=[mail])

Mail().sendmail():是我们的发送邮件函数,应该不必多说。

bless_info[mail]:是需要渲染的变量,这里面的变量少了可不行,多了没关系。

bless_info[mail][“title”]:就是刚刚在字典里指定的最后一个变量 title

由于 sendmail() 函数里的 receivers 是支持多人的,因此这里需要以数组的形式传入函数。

不过这里还有一个有趣的改进,如果你需要用同一个模板邮件发送给同一家人,你可以这么做:

bless_info = {
    ...,
    "test1@qq.com,test2@qq.com,test3@qq.com": {
        "pythondict_img": get_image_base64("./images/pythondict.png"),
        "name": "老王一家",
        "background": "https://背景图片.jpg",
        "bless": "祝王小女明年考研顺顺利利,老王全家幸福安康,吉祥如意..",
        "title": "老王一家,祝你们元旦快乐!"
    },
}

tm = Template(open('./index.html', encoding="utf-8").read())
for mail in bless_info:
    msg = tm.render(bless_info[mail])
    Mail().sendmail(html=msg, title=bless_info[mail]["title"], receivers=mail.split(","))

没错,只需要在key里将这一家人的邮箱用逗号分隔开,然后receivers里改为mail.split(“,”),你就能实现同一份邮件发给一家人的功能,是不是非常方便?

大家可以自己找喜欢的背景图片,也可以用我在代码里已给大家提供的图片。想要去除LOGO的话,直接将pythondict_img设为空,或者设为你自己的卡片即可。

在源代码目录下​运行代码:

python mail.py

即可成功发送邮件,快打开编辑器试一下吧(记得先测试)!

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

TheFuck—超实用的控制台命令纠正工具

The Fuck 是一款功能强大的、Python编写的应用程序,其灵感来自@liamosaur推文,可用于纠正控制台命令中的错误,如下图所示:

更多示例如:

自动识别没有权限,在命令前面添加 sudo:

➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

➜ fuck
sudo apt-get install vim [enter/↑/↓/ctrl+c]
[sudo] password for nvbn:
Reading package lists... Done
...

识别到没有推送到远程分支,自动追加:

➜ git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use
 
    git push --set-upstream origin master

➜ fuck
git push --set-upstream origin master [enter/↑/↓/ctrl+c]
Counting objects: 9, done.
...

识别到拼写错误:

➜ puthon
No command 'puthon' found, did you mean:
 Command 'python' from package 'python-minimal' (main)
 Command 'python' from package 'python3' (main)
zsh: command not found: puthon

➜ fuck
python [enter/↑/↓/ctrl+c]
Python 3.4.2 (default, Oct  8 2014, 13:08:17)
...

而且,如果你不担心fuck修正的结果是错误的,你可以禁用require_confirmation 选项,让fuck自动运行更正的命令:

➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

➜ fuck
sudo apt-get install vim
[sudo] password for nvbn:
Reading package lists... Done
...

在开发机上可以这么做,在生产机器上最好是谨慎一点,不推荐这么做。

1.安装

在OS X上,可以通过Homebrew(或在Linux上通过Linuxbrew)安装The Fuck

brew install thefuck

在Ubuntu / Mint上,使用以下命令安装The Fuck

sudo apt update
sudo apt install python3-dev python3-pip python3-setuptools
sudo pip3 install thefuck

在FreeBSD上,使用以下命令安装The Fuck

pkg install thefuck

在其他系统上, 使用pip安装The Fuck

pip install thefuck

2.配置

接下来需要把这个命令写入到 .bash_profile, .bashrc.zshrc 等启动脚本中。

根据你的终端类型,运行相应的命令即可:

Bash

chcp.com 65001 
eval "$(thefuck --alias)"

其中 chcp.com 65001 只有在windows环境下才需要运行。

Zsh:

eval "$(thefuck --alias)"

其他的可见:

https://github.com/nvbn/thefuck/wiki/Shell-aliases

3.原理

其实TheFuck的原理就是规则匹配(正则表达式),如果找到匹配规则的命令,则创建一个命令给用户选择或直接运行。

默认情况下的规则有:

  • cat_dir – 当你尝试cat目录的时候,用ls替换cat;
  • cd_correction – 拼写检查和纠正失败的cd命令;
  • cd_mkdir – 在进入目录之前创建目录;
  • cd_parent – 更改 cd..cd ..
  • dry – 修复类似的重复问题:git git push
  • fix_alt_space – 用空格字符代替Alt + Space;
  • git_checkout–修改分支名称或创建新分支;
  • … ….

等等,具体可以在官方文档中找到:
https://github.com/nvbn/thefuck

4. 创建自己的修复规则

要添加自己的规则,在~/.config/thefuck/rules 创建一个文件名为your-rule-name.py 的规则文件,必须包含两个函数:

match(command: Command) -> bool
get_new_command(command: Command) -> str | list[str]

下面是简单的 sudo 规则示例:

def match(command):
    return ('permission denied' in command.output.lower()
            or 'EACCES' in command.output)


def get_new_command(command):
    return 'sudo {}'.format(command.script)

# Optional:
enabled_by_default = True

def side_effect(command, fixed_command):
    subprocess.call('chmod 777 .', shell=True)

priority = 1000  # Lower first, default is 1000

requires_output = True

如果命令运行结果出现 permission denied 或者 EACCES,则执行 sudo xxx.

此外,还可以配置side_effect,如果你配置了enabled_by_default = True,side_effect函数内的操作将会被执行,本例中是对当前目录下的文件夹执行赋权操作: chmod 777 .​​

大家可以动手试试自己配一个修复命令。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

不限速真香!Python 转移文件至对象存储(COS)上

对象存储(Cloud Object Storage,COS)是一种存储海量文件的分布式存储服务,具有高扩展性、低成本、可靠安全等优点。

对象存储有什么用呢?比如说Python实用宝典网站的服务器位于腾讯云香港,大陆访问速度会比较慢,这时候我可以将图片等静态资源转移到对象存储上,以提高用户的访问速度。

实际上,这两天我就对Python实用宝典做了这样的调整,搭配上懒加载,效果极佳,用户访问并渲染图片的过程所耗费的时间大大减少,大家可以访问Python实用宝典网体验一下:

https://pythondict.com

那么对于非站长的普通用户有什么用?相比于其他什么百度网盘之类的产品,COS最重要的优势是:

  • 上传下载不限速,数据中心多地任选
  • 能实现文件分享功能,同样不限速
  • 能自动创建文件历史备份,方便回溯办公文件
  • 支持各平台用客户端管理文件,电脑端甚至还可直接将网盘挂载为一个虚拟磁盘
  • 价格按用量计费(存储量、下行流量),免费额度用完后,你可能一个月大约也才需要花费 6 元

像腾讯云这样的大云服务商,每个月都给用户提供了50G的免费容量:

非常好,下面大家可以跟着我一起尝试使用一下,或许你会爱上这个产品。

0.创建存储桶

进入腾讯云的对象存储页面:

https://console.cloud.tencent.com/cos5/bucket#

选择创建存储桶,可以随意命名你的数据桶,地域可以选择离你最近的。不过请注意访问权限这一项,如果你希望你的朋友也能下载数据桶内的文件,一定要选择公有读私有写:

1.安装

接下来说说怎么用Python将静态资源转移到腾讯云COS上。

Coscmd是腾讯云官方基于Python推出的上传工具,使用起来非常方便。

使用 pip 安装 coscmd

pip install coscmd

如果直接安装失败了,可以尝试源码安装

git clone https://github.com/tencentyun/coscmd.git
cd coscmd
python setup.py install

可以使用 coscmd -v 查看版本号

# coscmd -v
coscmd 1.8.6.16

2.配置

安装完成之后我们还需要一些参数配置,配置密钥、存储桶地域等。我们迁移数据时仅仅只需要配置一些简单的参数即可

coscmd config -a SecretID -s SecretKey -b BucketName-APPID -r region

SecretID 和 SecretKey 可以在控制台获取,如果没有的话直接创建一个:

BucketName-APPID 是存储桶名称,region 为存储桶所在地域,例如:

coscmd config -a AChT4ThiXAbpBDEFGhT4ThiXAbp**** -s WE54wreefvds3462refgwewe**** -b examplebucket-1250000000 -r ap-beijing

3.迁移

下面以迁移本地附件到 COS 为例,演示一下 COSCMD 的使用

COSCMD 可以上传文件也可以直接上传文件夹,命令为:

#上传文件
coscmd upload  

#上传文件夹
coscmd upload -r  

这样我们就可以使用如下命令将媒体库的文件上传到 COS 中

# home/ 指将媒体库里的文件存放到COS的home文件夹中
coscmd upload -r 你的媒体库文件夹地址 存放到COS的具体位置如home/

#同步上传,跳过 md5 相同的文件
coscmd upload -rs 你的媒体库文件夹地址 home/

#忽略 .mp3 和 .gif 的后缀文件
coscmd upload -rs 你的媒体库文件夹地址 home/ --ignore *.mp3,*.gif

我们需要将媒体库的图片上传到 COS 中,存放的路径则因使用而异。

如果是网站的话,比如WordPress 的媒体库存储路径建议使用 wp-content/uploads/,如果你是为了个人使用,可以上传到任意位置,建议使用:home/.

上传完成后如上图所示,你可以在文件列表中找到你刚上传的这些媒体文件。

当然,COS也支持手动上传文件:

如果你按照我的步骤创建了一个公有读私有写的数据桶,那么上传的这些资源也支持分享文件下载地址给别人:

上图中显示的对象地址,就可以拿来分享给你任何朋友下载,不限速!不限速!不限速!怎么样,是不是超香?

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 制作按键触发Windows通知的脚本

​对于键盘没有背光灯的同学而言,切换大小写或控制Num键开关的时候没有提示,经常需要试探性地输入一些字符来判断开关是否打开,体验非常糟糕。

因此,有人就想到自制脚本这一招,一旦触发大小写切换或Num键切换就进行windows通知提示:

https://github.com/skate1512/Toggle_Keys_Notification

今天我们来试试这个脚本,此外,我们还可以基于这个项目,扩展成任意一个按键被触发或切换都进行 windows 通知的脚本:

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

此外,推荐大家用VSCode编辑器,因为它可以在编辑器下方的终端运行命令安装依赖模块:Python 编程的最好搭档—VSCode 详细指南。

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install win10toast

除此之外,我们需要下载作者的代码,如果你能联通GitHub,请前往以下地址下载:
https://github.com/skate1512/Toggle_Keys_Notification

如果不能联通GitHub,或者网络速度比较慢,请在Python实用宝典公众号后台回复:按键触发通知 下载本文完整源代码。

2.源码使用与解析

2.1 源码使用

作者的项目可以在 Toggle_Keys_Notification 项目内,运行 notify.py 启动监听:

python notify.py

启动后点击一下大小写切换键,触发通知则说明代码正常运转:

2.1 源码分析

该项目通过win32gui和win32con实现了弹出toast进行通知的功能,最核心的_show_toast代码位于 toast.py 中,下面是这个函数的部分代码剖析:

注册和创建 window :

        message_map = {WM_DESTROY: self.on_destroy, }
        # 注册Window
        self.wc = WNDCLASS()
        self.hinst = self.wc.hInstance = GetModuleHandle(None)
        self.wc.lpszClassName = str("PythonTaskbar") # 定义该窗口结构的名称
        self.wc.lpfnWndProc = message_map
        try:
            self.classAtom = RegisterClass(self.wc)
        except:
            pass 
        # Window格式
        style = WS_OVERLAPPED | WS_SYSMENU
        # 创建Window
        self.hwnd = CreateWindow(self.classAtom, "Taskbar", style,
                                 0, 0, CW_USEDEFAULT,
                                 CW_USEDEFAULT,
                                 0, 0, self.hinst, None)
        UpdateWindow(self.hwnd)

所使用到的win32模块解析如下。

GetModuleHandle: 获取一个应用程序或动态链接库的模块句柄。
WM_DESTROY: 是关闭程序。
RegisterClass: 将定义好的Window属性保存保存下来。
WS_OVERLAPPED: 重叠式窗口,该式样窗口 带有一个标题栏和边框。
WS_SYSMENU: 具有 SYSTEM 菜单栏的样式
CW_USEDEFAULT: 采用系统默认位置

CreateWindow这个函数具有非常多的参数,甚至有一个百度百科来详细解析每一个参数的具体作用,大家感兴趣可以移步:
https://baike.baidu.com/item/CreateWindow/5076220

了解win32这些模块名称的意义后,理解上述代码的逻辑便很轻松了。

图标加载及任务栏图标显示配置:

        # 图标
        if icon_path is not None:
            # 获取图标地址
            icon_path = path.realpath(icon_path)
        else:
            icon_path = resource_filename(Requirement.parse("win10toast"), "win10toast/data/python.ico")
        # 加载格式
        icon_flags = LR_LOADFROMFILE | LR_DEFAULTSIZE
        try:
            hicon = LoadImage(self.hinst, icon_path, IMAGE_ICON, 0, 0, icon_flags)
        except Exception as e:
            logging.error("Some trouble with the icon ({}): {}"
                          .format(icon_path, e))
            hicon = LoadIcon(0, IDI_APPLICATION)

        # 任务栏图标
        flags = NIF_ICON | NIF_MESSAGE | NIF_TIP
        nid = (self.hwnd, 0, flags, WM_USER + 20, hicon, "Tooltip")
        Shell_NotifyIcon(NIM_ADD, nid)
        Shell_NotifyIcon(NIM_MODIFY, (self.hwnd, 0, NIF_INFO, WM_USER + 20, hicon, "Balloon Tooltip", msg, 200, title, NIIF_ICON_MASK))
        
        # 等待一会后销毁
        sleep(duration)
        DestroyWindow(self.hwnd)
        UnregisterClass(self.wc.lpszClassName, None)

这部分控制了通知弹出框的展示和销毁。如果你希望通知弹出框久一点再消失,可以适当修改传入的 duration 变量值。

DestroyWindow后,通知弹出框便消失了,整个 show_toast 的过程结束。

其实非常简单,从 CreateWindow 到 DestroyWindow 处理弹出框的各种属性,然后注销窗体,完成整个弹出流程。

3.扩展触发通知

为了扩展监听的按键,并能监听按键触发,需要先了解 notify.py 是如何检测到按键变化的。

获取按键状态:

keyboard = ctypes.WinDLL("User32.dll")
VK_NUMLOCK = 0x90
VK_CAPITAL = 0x14
def get_capslock_state():
    """Returns the current Caps Lock State(On/Off)"""
    return "Caps Lock On" if keyboard.GetKeyState(VK_CAPITAL) else "Caps Lock Off"


def get_numlock_state():
    """Returns The current Num Lock State(On/Off)"""
    return "Num Lock On" if keyboard.GetKeyState(VK_NUMLOCK) else "Num Lock Off"

可以看到,获取按键状态是通过 keyboard.GetKeyState(XXXX) 实现的。

而这个XXXX是对应的按键的十六进制,比如VK_NUMLOCK是Num键,对应的16进制代码是0x90,VK_CAPITAL是大小写按键,对应的十六进制代码是0x14.

变量名是可以用户自定义的,比如大小写键有些人习惯称之为VK_CAPITAL,也有些人喜欢称之为VK_CAPITAL,都可以,只要其最终对应的变量值为十六进制的0x14即可。

完整的按键16进制清单如下:

常数名称十六进制值十进制值对应按键
VK_LBUTTON011鼠标的左键
VK_RBUTTON022鼠标的右键
VK-CANCEL033Ctrl+Break(通常不需要处理)
VK_MBUTTON044鼠标的中键(三按键鼠标)
VK_BACK088Backspace键
VK_TAB099Tab键
VK_CLEAR0C12Clear键(Num Lock关闭时的数字键盘5)
VK_RETURN0D13Enter键
VK_SHIFT1016Shift键
VK_CONTROL1117Ctrl键
VK_MENU1218Alt键
VK_PAUSE1319Pause键
VK_CAPITAL1420Caps Lock键
VK_ESCAPE1B27Ese键
VK_SPACE2032Spacebar键
VK_PRIOR2133Page Up键
VK_NEXT2234Page Domw键
VK_END2335End键
VK_HOME2436Home键
VK_LEFT2537LEFT ARROW 键(←)
VK_UP2638UP ARROW键(↑)
VK_RIGHT2739RIGHT ARROW键(→)
VK_DOWN2840DOWN ARROW键(↓)
VK_Select2941Select键
VK_PRINT2A42Print键
VK_EXECUTE2B43EXECUTE键
VK_SNAPSHOT2C44Print Screen键(抓屏)
VK_Insert2D45Ins键(Num Lock关闭时的数字键盘0)
VK_Delete2E46Del键(Num Lock关闭时的数字键盘.)
VK_HELP2F47Help键
VK_030480键
VK_131491键
VK_232502键
VK_333513键
VK_434524键
VK_535535键
VK_636546键
VK_737557键
VK_838568键
VK_939579键
VK_A4165A键
VK_B4266B键
VK_C4367C键
VK_D4468D键
VK_E4569E键
VK_F4670F键
VK_G4771G键
VK_H4872H键
VK_I4973I键
VK_J4A74J键
VK_K4B75K键
VK_L4C76L键
VK_M4D77M键
VK_N4E78N键
VK_O4F79O键
VK_P5080P键
VK_Q5181Q键
VK_R5282R键
VK_S5383S键
VK_T5484T键
VK_U5585U键
VK_V5686V键
VK_W5787W键
VK_X5888X键
VK_Y5989Y键
VK_Z5A90Z键
VK_NUMPAD06096数字键0键
VK_NUMPAD16197数字键1键
VK_NUMPAD26298数字键2键
VK_NUMPAD36299数字键3键
VK_NUMPAD464100数字键4键
VK_NUMPAD565101数字键5键
VK_NUMPAD666102数字键6键
VK_NUMPAD767103数字键7键
VK_NUMPAD868104数字键8键
VK_NUMPAD969105数字键9键
VK_MULTIPLY6A106数字键盘上的*键
VK_ADD6B107数字键盘上的+键
VK_SEPARATOR6C108Separator键
VK_SUBTRACT6D109数字键盘上的-键
VK_DECIMAL6E110数字键盘上的.键
VK_DIVIDE6F111数字键盘上的/键
VK_F170112F1键
VK_F271113F2键
VK_F372114F3键
VK_F473115F4键
VK_F574116F5键
VK_F675117F6键
VK_F776118F7键
VK_F877119F8键
VK_F978120F9键
VK_F1079121F10键
VK_F117A122F11键
VK_F127B123F12键
VK_NUMLOCK90144Num Lock 键
VK_SCROLL91145Scroll Lock键

再来看看监听逻辑:

caps_curr = get_capslock_state()
num_curr = get_numlock_state()

while True:
    caps_change = get_capslock_state()
    num_change = get_numlock_state()

    if caps_curr != caps_change:
        if caps_change == "Caps Lock On":
            pop_up("Caps Lock On", "CapsLock_On.ico")
        else:
            pop_up("Caps Lock Off", "CapsLock_Off.ico")
        caps_curr = caps_change
        time.sleep(0.1)

    if num_curr != num_change:
        if num_change == "Num Lock On":
            pop_up("Num Lock On", "NumLock_On.ico")
        else:
            pop_up("Num Lock Off", "NumLock_Off.ico")
        num_curr = num_change
    time.sleep(0.2)

在刚开始运行监听脚本时,先获取到按键的状态,在循环体中,不断地获得当前按键状态,如果发生了状态变化,则触发pop_up函数,弹出刚刚我们提到的show_toast 函数:

def pop_up(body, icon):
    """Generates Pop-up notification when state changes"""
    notification = ToastNotifier()
    notification.show_toast("Lock Key State", body, icon_path="assets\\"+icon, duration=1.5)

整套监听并通知的机制还是非常简单的,如果我们想要自定义一些按键,你只需要在开头添加对应的按键的十六进制编码。

比如我们想监听 ESC 按键被按下:VK_ESCAPE=0x1B,使用 keyboard 模块添加一个钩子函数,监听按键:

import keyboard as kb
def hook_esc(button):
    """Alert if ESC button is pressed"""
    esc_button = kb.KeyboardEvent('down', VK_ESCAPE, 'ESC')
    if button.event_type == 'down' and esc_button.name == button.name:
        pop_up("ESC Pressed", "CapsLock_On.ico")
        # 敲击后回填为None
        button.event_type = None

然后再在循环体内添加判断逻辑:

kb.hook(hook_esc)

效果如下:

当然,图标和标题还可以进一步优化:

def pop_up(body, icon, toast_title="Lock Key State"):
    """Generates Pop-up notification when state changes"""
    notification = ToastNotifier()
    notification.show_toast(toast_title, body, icon_path="assets\\"+icon, duration=1.5)

比如将Lock Key State这个标题用 toast_title 变量替代,默认为Lock Key State。这样在调用pop_up函数的时候就能自定义标题了,效果如下:

总而言之,能扩展的东西非常多,这只是一个学习的例子,如果大家感兴趣的话可以在 Python实用宝典 公众号后台回复 按键触发通知 下载完整源代码进行改造。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

接近完美的监控系统—普罗米修斯

普罗米修斯(Prometheus)是一个SoundCloud公司开源的监控和告警系统。当年,由于SoundCloud公司生产了太多的服务,传统的监控已经无法满足监控需求,于是他们在2012决定着手开发新的监控系统,即普罗米修斯。

普罗米修斯(下称普罗)的作者 Matt T.Proud 在2012年加入该公司,他从google的监控系统Borgmon中获得灵感,与另一名工程师Julius Volz合作开发了开源的普罗,后来其他开发人员陆续加入到该项目,最终于2015正式发布。

普罗基于Go语言开发,其架构图如下:

其中:

  • Prometheus Server: 用数据的采集和存储,PromQL查询,报警配置。
  • Push gateway: 用于批量,短期的监控数据的汇报总节点。
  • Exporters: 各种汇报数据的exporter,例如汇报机器数据的node_exporter,汇报MondogDB信息的 MongoDB_exporter 等等。
  • Alertmanager: 用于高级通知管理。

1.怎么采集监控数据?

要采集目标(主机或服务)的监控数据,首先就要在被采集目标地方安装采集组件,这种采集组件被称为Exporter。prometheus.io官网上有很多这种exporter:exporter列表,比如:

Consul exporter (official)
Memcached exporter
 (official)
MySQL server exporter
 (official)
Node/system metrics exporter
 (official)
HAProxy exporter
 (official)
RabbitMQ exporter

Grok exporter

InfluxDB exporter
 (official)

等等…

这些exporter能为我们采集目标的监控数据,然后传输给普罗米修斯。这时候,exporter会暴露一个http接口,普罗米修斯通过HTTP协议使用Pull的方式周期性拉取相应的数据。

不过,普罗也提供了Push模式来进行数据传输,通过增加Push Gateway这个中间商实现,你可以将数据推送到Push Gateway,普罗再通过Pull的方式从Push Gateway获取数据。

这就是为什么你从架构图里能看到两个 Pull metrics 的原因,一个是采集器直接被Server拉取数据(pull);另一个是采集器主动Push数据到Push Gateway,Server再对Push Gateway主动拉取数据(pull)。

采集数据的主要流程如下:

1. Prometheus server 定期从静态配置的主机或服务发现的 targets 拉取数据(zookeeper,consul,DNS SRV Lookup等方式)

2. 当新拉取的数据大于配置内存缓存区的时候,Prometheus会将数据持久化到磁盘,也可以远程持久化到云端。

3. Prometheus通过PromQL、API、Console和其他可视化组件如Grafana、Promdash展示数据。

4. Prometheus 可以配置rules,然后定时查询数据,当条件触发的时候,会将告警推送到配置的Alertmanager。

5. Alertmanager收到告警的时候,会根据配置,聚合,去重,降噪,最后发出警告。

2.采集的数据结构与指标类型

2.1 数据结构

了解普罗米修斯的数据结构对于了解整个普罗生态非常重要。普罗采用键值对作为其基本的数据结构:

Key是指标名字,Value是该指标的值,此外Metadata(元信息)也非常重要,也可称之为labels(标签信息)。这些标签信息指定了当前这个值属于哪个云区域下的哪台机器,如果没有labels,数据有可能会被丢失。

2.2 指标类型

普罗米修斯的监控指标有4种基本类型:

1.Counter(计数器):

计数器是我们最简单的指标类型。比如你想统计某个网站的HTTP错误总数,这时候就用计数器。

计数器的值只能增加或重置为0,因此特别适合计算某个时段上某个时间的发生次数,即指标随时间演变发生的变化。

2.Gauges

Gauges可以用于处理随时间增加或减少的指标,比如内存变化、温度变化。

这可能是最常见的指标类型,不过它也有一定缺点:如果系统每5秒发送一次指标,普罗服务每15秒抓取一次数据,那么这期间可能会丢失一些指标,如果你基于这些数据做汇总分析计算,则结果的准确性会有所下滑。

3.Histogram(直方图)

直方图是一种更复杂的度量标准类型。它为我们的指标提供了额外信息,例如观察值的总和及其数量,常用于跟踪事件发生的规模。

比如,为了监控性能指标,我们希望在有20%的服务器请求响应时间超过300毫秒时发送告警。对于涉及比例的指标就可以考虑使用直方图。

4.Summary(摘要)

摘要更高级一些,是对直方图的扩展。除了提供观察的总和和计数之外,它们还提供滑动窗口上的分位数度量。分位数是将概率密度划分为相等概率范围的方法。

对比直方图:

直方图随时间汇总值,给出总和和计数函数,使得易于查看给定指标的变化趋势。

而摘要则给出了滑动窗口上的分位数(即随时间不断变化)。

3.实例概念

随着分布式架构的不断发展和云解决方案的普及,现在的架构已经变得越来越复杂了。

分布式的服务器复制和分发成了日常架构的必备组件。我们举一个经典的Web架构,该架构由3个后端Web服务器组成。在该例子中,我们要监视Web服务器返回的HTTP错误的数量。

使用普罗米修斯语言,单个Web服务器单元称为实例(主机实例)。该任务是计算所有实例的HTTP错误数量。

事实上,这甚至可以说是最简单的架构了,再复杂一点,实例不仅能是主机实例,还能是服务实例,因此你需要增加一个instance_type的标签标记主机或服务。

再再复杂一点,同样的IP,可能存在于不同云区域下,这属于不同的机器,因此还需要一个cloud标签,最终该数据结构可能会变为:

cpu_usage {job=”1″, instance=”128.0.0.1″, cloud=”0″, instance_type=”0″}

4.数据可视化

如果使用过基于InfluxDB的数据库,你可能会熟悉InfluxQL。普罗米修斯也内置了自己的SQL查询语言用于查询和检索数据,这个内置的语言就是PromQL。

我们前面说过,普罗米修斯的数据是用键值对表示的。PromQL也用相同的语法查询和返回结果集。

PromQL会处理两种向量:

即时向量:表示当前时间,某个指标的数据向量。

时间范围向量:表示过去某时间范围内,某个指标的数据向量。

如针对8核CPU的使用率:

知道怎么提取数据后,可视化数据就简单了。

Grafana是一个大型可视化系统,功能强大,可以创建自己的自定义面板,支持多种数据来源,当然也支持普罗米修斯。

通过配置数据源,Grafana会使用相应的SQL拉取并绘制图表,能直接看到普罗米修斯的各个指标数据图表:

更方便的是,Grafana有很多仪表盘模板供你使用,只要import模板进行简单的配置,就能得到以下效果:

5.应用前景

普罗米修斯非常强大,可以应用到各行各业。

5.1 DevOps

为了观察整个服务体系是否在正常运转,运维非常需要监控系统。在实例的创建速度和销毁速度一样快的容器世界中,灵活配置各类容器的监控项并迅速安装启动监控是非常重要的。

5.2 金融行业

金融服务巨头Northern Trust于2017年6月选择普罗米修斯,不是为了进行应用程序的监视,而是为了更好地了解其某些硬件的运作情况。Northern Trust使用普罗米修斯监控其平台上的750多种微服务。

5.3 汽车行业

Life360是一款用于定位、行车安全和家庭成员之间共享信息的移动应用程序,他们需要给用户提供稳定的定位服务,而原有的监控方案都非常局限,无法监视到所有组件的工作状态。

因此该公司使用普罗米修斯来监视其MySQL多主群集和一个12节点的Cassandra环,该环可容纳约4TB的数据。普罗米修斯在初步测试中表现良好。

在普罗米修斯的有限部署之后,Life360报告了监控方面的巨大进步,并设想在其数据中心基础架构的其他部分中使用它。 

总而言之,普罗米修斯这样的分布式监控系统,在未来的世界中用处可能会越来越大,它或许将会成为监控领域寡头式的存在,希望我们能熟悉这个工具,并在以后的架构和实践中使用它解决系统和应用监控的问题。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

人类训练AI的方式存在根本性缺陷

机器学习模型在实验室能被调整到近乎完美,但在现实环境中进行试验时,往往都会失败,这已经不是什么秘密了。这通常被归结为人工智能接受训练和测试的数据与它在世界上遇到的数据不匹配,这个问题被称为数据偏移(data shift)。

例如,经过训练,人类能够制造在高质量的医学图像中发现疾病迹象的AI,却难以分辨繁忙的诊所中廉价相机捕捉到的模糊或裁剪的图像。

这种现象被称为“数据不规范”(underspecification)。在机器学习世界中普遍存在。

数十名谷歌研究人员着眼于一系列不同的人工智能应用,从图像识别到自然语言处理(NLP)再到疾病预测。他们发现,“数据不规范”是这些项目表现不佳的原因。问题在于机器学习模型的训练和测试方式,没有简单的解决办法。

1.同样的模型,但表现不同

如果你阅读过我们前面的推文,你也知道建立一个机器学习模型需要在大量的数据源上进行训练,然后再在一堆模型没见过的数据源上进行测试,当模型通过测试时,模型就完成了。

谷歌人员指出,这样的判断标准太低了。事实上,训练过程可以产生许多不同的模型,即使这些模型都通过了测试,但他们内部存在许多细微的差异。比如神经网络不同节点的系数不同、被选择出来的关键因子不同。都会造成模型之间存在不同的差异。

这些差异,在模型通过测试的时候都会被忽略掉。而事实告诉我们,在现实世界中,这些细微的差异会导致巨大的表现差异。

这也就意味着,我们根本无法区分同一个算法训练出来的模型之间,哪个更适合在现实世界中运行,哪些模型根本不适合在现实生活中运行。

这与数据偏移不同,在数据偏移中,因为数据源和现实世界的实际情况不匹配,训练不能产生一个好的模型。但是在数据不规范中,你能产生许多通过测试的模型,但这些模型里掺杂着“好的模型”和“坏的模型”,它们只能通过在现实生活中实际应用来区分好坏。

研究人员研究了数据不规范对许多不同应用程序的影响,每种情况下,它们使用相同的算法训练产生多个机器学习模型,然后进行压力测试,突出它们在性能上的具体差异。

例如,ImageNet是一个日常物体的图像数据集,他们基于ImageNet上训练了50种版本的图像识别模型。每组训练的唯一区别是开始时分配给神经网络的随机值。然而,尽管所有50个模型在测试中的得分都差不多,但它们在压力测试中的表现却大相径庭。

压力测试使用ImageNet-C,这些图像被马赛克化或改变了亮度和对比度。另一个压力测试集是ObjectNet,一个日常物品的异常姿势图像集,比如倒立的茶壶,挂在钩子上的t恤。

50位模型里,有些在被马赛克化的图片上识别得很好,有些则在异常姿势上识别得很好;有些模型的整体表现比其他模型好得多。但其实就训练过程而言,它们都是一样的。

研究人员使用三种医学AI系统根据视网膜扫描预测眼病,从皮肤病变中预测癌症,从患者病历中预测肾衰竭。每个系统都有同样的问题:

那些本应同样精确的模型,在用真实世界的数据(如不同的皮肤类型)测试时,出现了不同的表现。这并不是训练集/测试集不够导致的,而是不论训练集/测试集多大都会出现这样的问题。

因此研究人员罗勒说,我们可能需要重新考虑如何评估神经网络。“我们的基本假设中出现了一些重大漏洞。”

人类现在使用的大多数机器学习模型的训练逻辑,其实都无法被证明是有效的。

2.解决方案

一种选择是在训练和测试过程中设计一个额外的阶段,在这个阶段中可以同时生产多个模型,而不是只生产一个。然后,这些相互竞争的模型可以在具体的现实任务中再次进行测试,以选择最适合这项工作的模型。

但这样需要做很多工作。苏黎世联邦理工学院的机器学习研究员Yannic Kilcher说,对于像谷歌这样建造和部署大型模型的公司来说,这样做是值得的。谷歌可以提供50种不同版本的NLP模型,应用程序开发人员可以选择最适合他们的一个。

目前研究人员们还没有解决这个问题,但正在探索改进培训过程的方法。当人工智能在现实世界中表现不佳时,人们就不太愿意使用它了。因此,如果这个问题没有尽早得到有效的解决,这个时代的人工智能浪潮或许将就此平息。

译自technologyreview, 《The way we train AI is fundamentally flawed》。

我们的文章到此就结束啦,如果你喜欢今天的Python 文章,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典