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

抓取box.net分享连接的python脚本

通过前面写的注册机,我已经在box.net注册和上传了很多文件。

现在把自己提取分享连接的脚本发布出来。

这段脚本只是模拟各种http请求:登陆,查看文件夹,翻页,逐个分享文件,解析json

让人感觉麻烦一点是token和cookie。

token在切换文件夹的页面产生了变化,也曾让我在写代码的过程中遇到过疑惑。

Crawler类通过用户名和密码构造,login方法尝试登陆:

crawler = Crawler('your_email', 'your_password')
crawler.login()

ls方法用于列文件,必需的参数是一个文件夹名,

sorted_by参数是可选的: name, date, size

sorted_direction参数是可选的: ASC, DESC

lst_files = crawler.ls('a_folder_name', sorted_by='date', sorted_direction='ASC')

ls方法返回的是一个列表,而列表中的每个元素都是元组tuple。

这个tuple的形式是: (文件名, 分享链接)

 

这段代码的效率较低,

因为文件是逐个分享的,没有使用多线程,而http请求和解析json的次数过多。

查阅代码

 

解决python urllib2 302重定向后丢cookie的问题

通过昨天写的python脚本,我已经注册激活了50个box.net账号,用作上传文件。

今天我继续写代码,用来自动登录box.net并获取所有文件的分享链接。

不过测试的时候出现了点问题,账号信息正确,但总是登录不成功。

headers中referer、user-agent都有伪造,cookie也有发送。

通过设置debuglevel=1跟踪http请求,最终发现了问题:

        httpHandler = urllib2.HTTPHandler(debuglevel=1)
        httpsHandler = urllib2.HTTPSHandler(debuglevel=1)
        self.opener = urllib2.build_opener(httpHandler, httpsHandler)

urllib2很聪明,在发现HttpResponse中有重定向(301, 302)时会自动转向请求这个新的URL,

但urllib2有个严重的问题,它没有带着cookie去请求新的URL。

这也是说,前期我们通过一个POST请求来获取cookie(对应着服务器上的session),

但urllib2却没有带着必要的cookie去访问需要授权的页面。

一开始我是想直接用httplib的,考虑到前后一致性才全部用urllib2,结果urllib2又出问题。。。

解决这个问题,可以:

1. 换httplib来实现,它不会像urllib2会自动处理重定向,cookie不会丢

2. 截获重定向,禁止urllib2自动处理

我选择了重写urllib2.HTTPRedirectHandler的http_error_302方法,截获302,让urllib2不再处理302:

class HttpRedirect_Handler(urllib2.HTTPRedirectHandler):
    def http_error_302(self, req, fp, code, msg, headers):
        pass

然后在urllib2.build_opener方法中用HttpRedirect_Handler的一个实例做参数,例如:

self.opener = urllib2.build_opener(HttpRedirect_Handler(),
                                   urllib2.HTTPCookieProcessor(self.cookie))

这样,当我们用上述opener去POST登录时,遇到302就不会再自动转向了,

登录成功获取到的cookie也不会丢。

后面再带着self.cookie去请求需要授权的页面,就可以获取到正确的内容了。

 

批量注册Box.net账号的python脚本

国内网盘上传速度实在太慢了(跟运营商也有关系),没办法,我只好选择国外的网盘。

但国外网盘一个最大的问题是,容量小,dropbox起始2GB,而google Drive也才5GB。

最终我选择的是box.net网盘,10GB,并且外链非常容易编程获取。

web上传大约2M/s,甚至不用客户端。

如果上传500GB的文件,将需要超过50个账号,手工注册太麻烦,于是写下一小段python脚本:

1. 注册表单位于: https://app.box.com/signup/personal/

2. 在上述页面可获取request token和cookie

3. 自己构造表单信息后提交

选择批量注册,另一个比较重要的原因,是我的邮箱域设置了自动转发。

对于不存在的用户,比如[email protected], [email protected]

都将转发到一个指定的管理员邮箱,比如[email protected]

所以,所有的激活邮件都将直接发送给我自己,激活也比较方便,不用登陆不同的邮箱。

代码在这里

代码中的例子是注册[email protected][email protected]这种形式的账号。

 

最后还想说一句:屌丝用户伤不起,买个网盘都嫌贵。。。

 

一个简单的python日期字符串格式化函数

之前从豆瓣音乐上爬了大概98万个专辑,包括各个专辑的参数。

为了处理专辑的发布日期,我写了一个简单的日期格式化函数。

豆瓣音乐上的日期没有统一规范,还包含不少错误,混乱,甚至无关的文字。

但正确出现的日期字符串,则主要有这几种形式:

10 December, 1991

30 June 1992

April 13, 1999

December 1994

June, 1992

2004 03

2002年08月05日

2004年6月

2002年

我需要的最终格式是:

2013-09-15

2013-09

2013

源代码在:  https://github.com/lijiejie/format-date-str

请传入一个unicode字符串

BeautifulSoup的innerHTML实现

innerHTML方法用于提取某个标签内部的HTML内容,多数HTML Parser都实现了该方法。

BeautifulSoup暂未提供innerHTML方法,但我们可以通过遍历子元素并拼接html来实现它。

例如,我需要获取豆瓣音乐上某个专辑的描述信息,它位于一个id为info的div中。

参考:http://music.douban.com/subject/1394539/

我需要图示部分的html代码:

info-div

这时只需要一行代码:

album_info = u''.join([unicode(x) for x in soup.find('div', id='info').contents]).strip()

值得注意的是,豆瓣音乐的网页编码是utf8,需要先decode utf8再parse。

而在Beautiful内部,所有对象都是unicode object。

contents属性返回所有child element的列表。

因为我是在windows中文版的系统下写这段脚本,当需要在命令提示符下输出内容的时候,还必须先encode gbk。

print album_info.encode('gbk', 'ignore')

 

参考链接:

http://stackoverflow.com/questions/8112922/beautifulsoup-innerhtml