django makemessages时出现DjangoUnicodeDecodeError

今天对www.fachun.net做了些改动,需要增加一点翻译。

当我执行django-admin.py makemessages -l en时,遇到了DjangoUnicodeDecodeError,

DjangoUnicodeDecodeError: ‘utf8’ codec can’t decode byte 0xcd in position 12: in
valid continuation byte. You passed in ‘2013/10/11 \xcd\xea\xb3\xc9\xc1\xcb\xd5
\xbe\xb5\xe3\xb5\xc4\xb9\xfa\xbc\xca\xbb\xaf\xa3\xac\xb2\xb9\xb3\xe4\xc1\xcb\xd3
\xa2\xce\xc4\xb7\xad\xd2\xeb\n\n2013/10/12 \xca\xb5\xcf\xd6\xc1\xcb\xa1\xb0\xbb
\xbb\xd2\xbb\xc5\xfa\xb9\xa6\xc4\xdc\xa1\xb1\xa1\xa2\xd4\xda\xb2\xbb\xcd\xac\xd3
\xef\xd1\xd4\xd1\xa1\xd4\xf1\xcf\xc2\xb8\xdf\xc1\xc1\xb2\xbb\xcd\xac\xb5\xc4\xce
\xc4\xd7\xd6,\xca\xb5\xcf\xd6\xc1\xcb\xb6\xe0\xd3\xef\xd1\xd4URL\xb2\xee\xd2\xec
\xbb\xaf\xb5\xc4\xd3\xc5\xbb\xaf\n\n2013/’ (<type ‘str’>)

看名字知道是出现了uniocde解码错误。

但自己一向非常注意编码问题,数据库、文件都是以utf8编码保存的。

因为错误信息没有提到是在哪个文件出现问题,

我在python里将上述字符串打印出来,发现竟然是更新记录:

DjangoUnicodeDecodeError-print

这样就定位到出现问题的文件,它是app目录下的一个logs.txt文件。

按个人理解,这个文件是不应该被makemessages处理的,它既非模板,又不是.py文件或.po文件。

但makemessages不想遗漏需要处理的文件,也可以理解。

为什么这个文件会出现问题呢?因为它是我用记事本在windows下直接创建和保存的。

在windows下,记事本默认地将这个文件以”ANSI code page”编码保存。

我使用win7中文版(codepage = 936),文件就默认以GBK编码保存,跟我在cmd下默认是gbk编码一样。

 

知道了出错的原因,再次用记事本打开文件,另存utf8就行了。

不得不说,windows的记事本真是很奇葩。

有Ctrl + S保存习惯的同学可以考虑Alt + F + A另存为utf8,或者用editPlus

抓取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]这种形式的账号。

 

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

 

各家网盘在国外VPS上的性能对比

最近几天我在向自己的网盘上传几百GB的文件,用作分享。

自己在杭州的住处使用12M ADSL,下行速率可以达到1.5M/s,但上传速率仅仅200kb/s左右。

传了两三天,发现实在受不了,于是买了个廉价的美国VPS用作上传。

简单对比各家网盘:

360云盘 百度网盘 DropBox 华为网盘 腾讯微云
容量 36 TB 2 TB >50 GB 大约30 GB 10TB
上传 

速率

150 kb/s 100 kb/s > 2M/s 250 kb/s 100kb/s以下
离线 

下载

http(最大并发10任务) http/bt
外链 

分享

方便 较方便 方便 不太方便 较方便
优点 容量大、编程获取链接方便 下载快、BT离线下载、 

秒传、容量大

上传快,分享方便 中庸
缺点 上传慢、下载速度一般 上传慢 容量非常小、收费高

总结一下:

1. 印象很深的是,我位于洛杉矶机房的VPS,dropBox上载速率超过2M/s,其他网盘远不可及

2. 如果是http资源离线下载,360网盘的效率高于百度网盘,目测5倍左右。 当然,我下载的资源是别人没有下过的

3. 国内这些网盘把自己的容量吹嘘得很大,实际上都对上传速率做了限制的

想想看,上传200GB的文件就要传半个月才能传完!那他给你10个TB有什么用?

也只能是存一些像电影的大文件罢了,

像这种热门资源,云端是不需要为每个人都分别保存一份的,只是一个指向对应资源的链接。

仅此而已。

Django i18n多语言的URL差异化解决方案

昨天我已经对站点“春天音乐”进行了国际化,添加了英文翻译。

但当时后端是根据session和cookie记录用户的语言设定,

这造成的问题是,同一URL,存在一个中文版、一个英文版。

搜索引擎的爬虫进入后,大多只能抓取并保存对应的中文版(默认语言),而遗失了对应的英文版。

因此,必须对中文版和英文版进行URL差异化。有两种选择:

1. 增加一个参数,类似 http://www.fachun.net/?lang=en

2. 增加一个前缀,类似 http://www.fachun.net/en/

因为第二种更好看,我选择了第二种。整个实现过程较繁琐,下面提供我采用的解决方案。

1. 安装django-localeurl

我安装的版本是2.0.1: https://pypi.python.org/pypi/django-localeurl

该程序包的作用,是允许你在URL中设定语言,而不需要修改原有的URL配置(urls.py中的设置)。

安装完成后,编辑settings.py文件配置:

LANGUAGE_CODE = ‘zh-CN’
LANGUAGES = {
(‘zh-cn’, ‘中文’),
(‘en’, ‘English’),
}
PREFIX_DEFAULT_LOCALE = False
LOCALEURL_USE_ACCEPT_LANGUAGE = True

MIDDLEWARE_CLASSES = (
#’django.middleware.cache.CacheMiddleware’,
‘django.contrib.sessions.middleware.SessionMiddleware’,
‘localeurl.middleware.LocaleURLMiddleware’,
‘django.middleware.common.CommonMiddleware’,

#’django.middleware.locale.LocaleMiddleware’,

)

INSTALLED_APPS = (

..

‘localeurl’,

)

几点说明: 继续阅读Django i18n多语言的URL差异化解决方案