python和tkinter写了一个豆瓣音乐下载工具

前天自己的阿里妈妈账号再次被冻结了,好不容易有5000多收入,一下又没了。

没办法,还是拿自己的一点小手艺,赚点吃饭的钱,花一天时间写了这个小工具。

douban-music-downloader

可以下载豆瓣的红心兆赫、豆瓣小站大部分专辑。下载任意兆赫的功能没有写,时间有限。

douban-downloader-main

这个程序我希望能够收费提供,所以虽然公开代码,但并不希望你生成无限制的exe免费提供,请谅解。

Tkinter是single-threaded,记住这一点比较重要。 对于耗时的操作,比如下载,需要创建新的线程来完成。

我在程序启动时创建了5个daemon线程,用于下载MP3,一般,5个线程就足够达到较好的下载效率。

windows可执行文件 (请注意,文件夹名称中不能存在中文)

下载源代码 (如果你做了任何改进,欢迎提交给我。 :))

Python命名空间和作用域的基本认识和一点小魔法

作为初学者,简单总结自己对Python命名空间(namespace)和作用域(scope)的认识。

Python在名称空间搜寻变量和函数的顺序可以认为是:

函数内部 -> (嵌套)父函数内部 -> 模块内部 ->  built_in内置模块

1. 函数内部(local)

简单举例说明:

x = 123

def func():
    x = 456
    print 'inner x =', x

func()
print 'outer x =', x

输出:

inner x = 456
outer x = 123

模块级变量x的值是123,而在函数func内部,local变量x的值是456。可以看到,函数是没有改变外部x的值的。

2. 父函数内部 继续阅读Python命名空间和作用域的基本认识和一点小魔法

python sys.setdefaultencoding的一点小魔法

python中调用sys.setdefaultencoding方法可以修改默认编码。

但是这个方法调用有一些特别。在python解释器中执行:

>>> import sys
>>> dir(sys)

输出为:

['__displayhook__', '__doc__', '__egginsert', '__excepthook__', '__name__', '__p
ackage__', '__plen', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache
', '_current_frames', '_getframe', '_mercurial', 'api_version', 'argv', 'builtin
_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayh
ook', 'dllhandle', 'dont_write_bytecode', 'exc_clear', 'exc_info', 'exc_type', '
excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_
repr_style', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencoding',
'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'gettrace', 'getw
indowsversion', 'hexversion', 'long_info', 'maxint', 'maxsize', 'maxunicode', 'm
eta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', '
prefix', 'ps1', 'ps2', 'py3kwarning', 'setcheckinterval', 'setprofile', 'setrecu
rsionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', '
version_info', 'warnoptions', 'winver']

会看到实际上sys模块中并没有这个所谓的setdefaultencoding方法。

文档中描述为:这个方法是为site模块的调用而准备的,而一旦被调用之后,它将会被从sys的名称空间中抹掉。

This function is only intended to be used by the site module 
implementation and, where needed, by sitecustomize. Once used 
by the site module, it is removed from the sys module’s namespace.

而如果确实有需要调用这个方法,可以使用reload再次导入这个模块:

import sys  

print 'old encoding value:', sys.getdefaultencoding()
reload(sys)
sys.setdefaultencoding('utf8')
print 'new encoding value:', sys.getdefaultencoding()

输出为:

old encoding value: ascii
new encoding value: utf8

Python Tkinter写的一个POST工具[源代码]

昨天想复习一下使用Tkinter开发GUI程序,练手写了一个简单的POST工具。    源代码

必须的package有:

前者用于在linux下显示GIF窗口图标,后者用于检查文本编码,以便完成自动解码unicode。

写代码过程中遇到的问题有:

  1.  linux和mac下的图标问题
  2.  窗口屏幕居中的问题
  3.  Tkinter不支持多线程

对于第三个问题,因为Tkinter是单线程的,因此捕获到按钮点击后,需要创建另一个线程完成post动作。

自然,也可以在command对应的函数中完成HTTP请求了,但会面临窗口不能及时响应的问题。

也就是说,在HTTP请求结束前的一两秒内,窗口是无响应的。

另外,也正因为Tkinter不支持多线程。

错误提示将以红色的文本显示在Response相应的文本框中,而不是消息框提示。

在另一个线程改变文本框的内容是安全的,但创建MessageBox就不是这么回事了。

TkPostTool

Tkinter窗口在屏幕居中的问题

为了让程序窗口在不同的平台和计算机上都能良好的显示,需要考虑:

1. 窗口的大小

2. 窗口的位置

对于第一点,因为默认字体不同,应该尽量避免固定长宽,而让geometry manager(图形管理器)自己去计算所需的大小。但可以设置各个部件之间的间隙大小。

对于这一点,我还想提一下tkinter中的entry和text这两个widget,他们的height和width都是表示可以输入的英文字数,而不是像素值。只有这样,同样的文本内容,才可以在windows、linux下展现一致。而不会windows下在A处换行了,而ubuntu却在B处换行。

Tkinter的窗口屏幕居中有点烦人,没有现成的method,但我找到了一种可行的方法。简单说明:

1. 屏幕的分辨率是非常容易获取到的,直接通过root.winfo_screenwidth()、root.winfo_screenheight() 继续阅读Tkinter窗口在屏幕居中的问题

Tkinter在Ubuntu设置窗口图标遇到的问题

使用Tkinter Package来开发Python GUI程序是非常迅速的,但是它的一些细节不太完美。

在windows环境,设置窗口图标只需要一行代码:

root.iconbitmap(default='myicon.ico')

但这行代码在Ubuntu上无法正常工作,提示myicon.ico not defined。

实际上,我在ubuntu上将图标换成一个x bitmap,依然无法正常工作。

解决在Ubuntu和Mac上出现的这个问题:

1. 安装PIL(python imaging library),支持更多的图像格式,建议制作gif格式64×64做为图标

2. iconbitmap函数封装了tk的iconbitmap窗口消息,我们换成使用Tkinter一个未封装的iconphoto消息

3. windows和linux可以使用同样的代码,也可以根据os.name分支

 

安装PIL

PIL的地址是:http://www.pythonware.com/products/pil/,我选择的是最新的1.17

下载解压之后,还不能立即安装,执行:

apt-get install python-dev

apt-get install libjpeg-dev

前者提供需要的头文件,后者安装了所需的jpeg decoder。

然后,在setup.py中跳到214行

add_directory(library_dirs, "/usr/lib")

在它前面添加:

add_directory(library_dirs, "/usr/lib/i386-linux-gnu")

参考: http://stackoverflow.com/questions/8479344/pil-encoder-jpeg-not-available

随后即可正确安装:

./setup.py build

./setup.py install

我们的python代码可以这样写:

from ImageTk import PhotoImage
icon = PhotoImage(file='icon.gif')
root.tk.call('wm', 'iconphoto', root._w, icon)

可以看到这里是发送的window message iconphoto。

windows下效果:

tkinter-icon-windows

Ubuntu VPS上截图:

tkinter-icon-ubuntu