存档

文章标签 ‘google code’

Tweets2PDF开发手记

三月 1st, {2011 5 条评论 8,725 人阅读过  

之前一直想学一下Python却迟迟未曾下手,直到过年前几天好不容易闲下来,突然有个想法想把Twitter上发的tweets备份成PDF,我这个人一有了什么想法就会立马动手去做,于是正好借这个机会学下Python,没有太多时间,用Python比用C会节省很多开发时间,于是折腾了几天就有了这样一个小工具,Tweets2PDF,趁着还没把看过的东西忘光就先记录下写开发过程。

Twitter使用OAuth认证,其实之前对OAuth的原理也不是很了解,正好也借这个机会简单看了一下它的原理。

首先,程序需要向Twitter官网申请一个consumer token,每个客户端需要持有这个token,OAuth开始的时候向Twitter的Request Token URL发送请求来获取一个Request Token,当然HTTP请求中需要加上一些参数,这些参数中包含了Consumer Token相关的值,当然不止这些,具体的参数内容就去参考Twitter上OAuth的介绍或者去读OAuth的RFC。

获取到Request Token之后再根据这个Token生成一个URL,在浏览器中打开这个URL就可以对应用程序进行认证,有一个请求参数是Callback参数,它可以是一个URL,表示验证成功之后程序跳转到该URL,这个URL是Consumer的URL,这适合Web形式的第三方程序,桌面应用程序大家如果用过肯定都知道是需要一个PIN码的,如果要让Twitter返回这个PIN码,只需要把Callback的值设为oob即可,这样在认证之后Twitter后给出一个PIN码。

将这个PIN码由用户交回桌面应用程序,应用程序便再利用这个PIN码和Request Token再生成一个HTTP请求,这个请求成功之后会获取一个Access Token,这个Token是需要用户保存的,之后对于Twitter的访问只需要在请求中根据这个Token生成添加相应的HTTP请求参数即可,Twitter就会知道这个应用程序是经过认证的。

关于Twitter OAuth认证的详细资料见:Authenticating Requests with OAuth

OAuth认证过程中设计到对请求参数的处理比较繁琐,这方面的工作已经有人做过了,我没有必要做无用功,用了这个OAuth库: http://oauth.googlecode.com/svn/code/python/ 不过这个库貌似有些问题,用它的Demo跑的时候会出问题,我对它做了一些修改,并在它之上完成了Twitter的OAuth认证。

不得不说OAuth这种认证机制是Web2.0的开放平台的必然产物,也是这种开放平台所必不可少的,它可以让不同的服务或者程序访问彼此开放的资源,这种开放平台策略也是互联网发展的趋势,可不明白的是为什么国内这么多SNS服务却没有一个能把开放地平台给做好,Twitter有非常多优秀的第三方客户端,可没有听说谁觉得有哪个什么第三方的新浪微博客户端好用,可能他们认为开放会带来风险,但开放更多地会带来商机,更多的人使用Twitter的第三方官户端去发推,但Twitter却越做越好,这是开放平台的魅力。

晕,扯远了,接着说Tweet2PDF,经过认证之后就可以很简单地通过Twitter提供的API来获取相关的数据了,Twitter的API非常丰富,用官方版本能做的事情用API都可以做,它的API除了每小时有访问限制(可能出于服务器负载的考虑)之外,它的API非常完整,当然说到API的限制我也遇到了问题,对于一般的第三方官户端程序来说API是够用的,但我要做的是抓取用户发过的所有Tweets将其生成PDF,这个过程中会一直不间段地大量抓取,难免会遇到API受限,这种情况下我只能进行重试,由最初的3次重试调整为现在的10次,基本可以保证用户正常抓取完所有的推后中止,但还有一个问题,Twitter的API只允许抓取最新的3200条Tweets,对于再旧的Tweets就抓取不到了,这便降低了这个软件的可用性,因此它只能用来给用户进行定期备份了。

抓取到数据之后便要生成PDF文件了,生成PDF用的是Reportlab这个库,很幸运,它是用Python写的,用Python对它进行调用很完美,而且它有开源版本,Reportlab需要PIL(Python Imaging Library)的支持,来进行图片的处理,实现的细节就不说了,官方有很详细的文档,遇到几个小问题:

因为每生成一条Tweet都会在前面附上发推人的Profile Image,Reportlab对JPEG格式的图片支持很好,但如果图片是其它格式,例如PNG,当生成页数过多时在调用Build函数进行生成时便可能出错,这个错误是无法挽回的,也就是说前出抓取到的Tweet可能全部都前功尽弃了,我尝试了很多方法都没有解决这个问题,不确定是不是Reportlab自身的BUG,但我也有自己的解决方法,既然JPEG格式完美支持,那就在抓取到Image之后将先用PIL转换成JPEG再进行Build,这样便不会有问题了,不过对效率有少许的影响,因为转换的过程会花一些时间,图片一多的话会比较慢,但这个可以忽略,别人不会天天都拿来用,而且小数据量不会感觉到慢,偶尔过个几个月用一次多花点时间备份也无所谓了,只要保证可以正确生成就好了。

PDF可以不出错地生成之后我便发布了第一个Beta版本,虽然用的人不多,不过用过的人评价还不错,这也让我这个Python新手很受鼓舞,于是用PyGTK开发了GUI版本,之前用GTK给OPENFETION作的UI,对GTK比较熟悉,PyGTK就更简单不过了,花了一个晚上就把界面给做好了,当然很多细节的功能花了我一天多去完善,最后一天完全扔在了Windows打包上,太痛苦了。。。

接下来记录几个写Python几个小的Tips吧

1. 给PDF页面加脚注和页码:

Reportlab 对生首页和后续页面的处理,定义两个回调函数,如下:

def on_first_page(canvas, doc):   
	canvas.saveState()   
	canvas.setFont('song', 9)
	canvas.setFillColor('grey')
	footer = 'Generated by Tweets2pdf at %s' % \
	time.strftime('%a %b %d %H:%M:%S %Y', time.localtime())
	footer += ' Powered by @levin108'
	canvas.drawCentredString((PAGE_WIDTH)/2, 25, footer)
	canvas.restoreState() 
 
def on_later_pages(canvas, doc):   
	canvas.saveState()   
	canvas.setFont('song', 9)   
	canvas.drawString((PAGE_WIDTH/2)-5, 25, u"%d" % (doc.page - 1))   
	canvas.restoreState()
 
pdfdoc.build(elements, onFirstPage = on_first_page, onLaterPages = on_later_pages)

两个回调函数分别表示对首页和后续页面的处理,然后将这两个回调函数传给Build函数进行生成,在这里我给首页加了脚标,给后续页底部加了页码,最终Build在生成PDF的过程中会给每个页面做相应的处理。

2. 中文自动换行的设置

下面这段代码是我从网上搜到的,具体我没去研究,给Paragraph这个Flowable控件重定wrap方法便可以Paragraph中的内容实现自动换行:

def wrap(self, availWidth, availHeight):
	# work out widths array for breaking
	self.width = availWidth
	leftIndent = self.style.leftIndent
	first_line_width = availWidth - (leftIndent+self.style.firstLineIndent) - self.style.rightIndent
	later_widths = availWidth - leftIndent - self.style.rightIndent
	try:
		self.blPara = self.breakLinesCJK([first_line_width, later_widths])
	except:
		self.blPara = self.breakLines([first_line_width, later_widths])
	self.height = len(self.blPara.lines) * self.style.leading
	return (self.width, self.height)
Paragraph.wrap = wrap

3. PIL转换转换图片格式

img = Image.open(filename)
if img.mode != 'RGB':
	img = img.convert('RGB')
img.save(outname, 'JPEG')

其实只要第一行和最后一行便可以实现格式转换,但在其它格式转成JPEG的时候可能会有异常,所以需要先转换成RGB模式,然后再保存在JPEG。

4. 关于在浏览器中打开URL

之前一直都是用system(‘xdg-open …’)来在浏览器中打开URL的,但这种方法不能保证跨平台,Python有自己的相关模块Webbrowser

import webbrowser
webbrowser.open_new_tab(URL)

上面的语句表示在新标签页中打开URL

5. Windows移植
关于在Windows系统中的移植到是没花太多功夫,主要是一些关于路径的设置,但打包折腾了近一天的时间对弄了个勉强可以在Win7下面跑的版本,p2exe问题太多了,不搞了,还是等有兴趣有经验的牛人来搞吧。

以上是我开发过程的总结,新手欢迎拍砖~~~

分类: Python 标签: ,

SVN使用小结(在google code上管理代码)

四月 6th, {2010 3 条评论 11,661 人阅读过  

前几天发布了openfetion的新协议版本,在Ubuntu中文论坛上发了个贴子宣传了一下,Ubuntu在中国果然不愧是拥有最状大的用户群,以前在其它的开源社区发的时候点击率都很低(当然也可能是大家觉得这个很没意思),不过这次Ubuntu论坛里面的网友们让我很感动,大家回馈了丰富的修改意思,也提交了各种现存的bug,还有的网友帮我打了deb包和rpm包,甚是感动,在这里先谢一下,由于bug太多,一个多星期的时候更新了两个版本,本来这个东西就是做出来玩玩的,看来还是有很多人喜欢的,所以我也决定用继续用我的休息时间把它做下去,之后考虑加上文件传输和非移动号码登陆这些有用的功能。

OK,扯远了,这篇文章是要总结一下svn的用法的,很多人发邮件问我关于飞信相关协议的问题,我也都给一一回复了,可也着实花费了不少的时间,后来就写了几篇相关的文章,仍然有人对一些细节不解,没办法,后来我也管不了那么多了,就把飞信给完全开源了,希望我的行为能对祖国的开源事业做一点小小的贡献吧。

突然觉得sourceforge和google code的svn代码管理很有用,以前在服务器上搭过cvs,后来嫌麻烦就一直没用,看了看svn的一些介绍,发现用起来着实简单方便了不少,于是就想用一用了,本来想在实验室服务器上搭一个的,后来想既然开源了就放到网上跟大家共享吧,gg去香港后在实验室上就很不稳定了,偶尔上得去偶尔上不去,于是想放到sf上去,结果sf的svn服务器教育网不加代理访问不了,抓包看了下svn的协议是TCP承载的TLS,只有http的代理,也不知道行不行,懒得研究就用gg了。

又扯了一大堆费话,总结一下svn的基本命令吧。

svn checkout :简写是svn co
example:

$svn checkout https://ofetion.googlecode.com/svn/trunk/ ofetion –username levin108

这个没什么好说的,跟cvs的checkout一个意思,从版本库中取出一个项目的拷贝,输入后会提示输入验证码,验证通过后会提示是否以保存在本地,保存的话以后就不用输入了。

svn commit :简写是svn ci
example:

$svn commit -m “modified some bugs”

将本地项目拷由的修改提交到版本库藏, 不加-m会的话提示一些乱七八糟的东西,没细看。

svn copy :简写svn cp

复制本地项目副本到版本库

svn move (mv), svn delete (rm,del),svn mkdir

故名思义吧,跟copy差不多,懒得说细地写了。这些操作所做的修改都会保存到本地缓存中,执行svn ci后才会同步到版本库。

svn import
example:

$svn import -m “initial import” https://ofetion.googlecode.com/svn/trunk/ ofetion –username levin108

递归地把一个目录下的文件提交到版本库,这个目录提交上去后它里面并没有版本库信息,我觉得应该在执行完这条命令后就应该在所有的目录中创建.svn文件夹,以保存版本库信息的。

所以就只能再把版本库中的项目checkout下来,这样的话各目录中就有了版本控制信息了,就可以进行版本控制操作了。

svn blame
example:

$svn blame Makefile.am

2 levin108 SUBDIRS = src include skin resource
2 levin108
2 levin108 EXTRA_DIST = LICENSE LICENSE.OpenSSL
2 levin108
2 levin108 install: install-recursive
2 levin108 @echo “———————————————————-”;
2 levin108 @echo “| |”;
2 levin108 @echo “| OpenFetion 1.2 by lwp(levin108@gmail.com) |”;
2 levin108 @echo “| |”;
2 levin108 @echo “| OpenFetion a fetion client for linux based on GTK+2.0,|”;
2 levin108 @echo “| using Fetion Protocol Version 4. It supports most |”;
2 levin108 @echo “| useful functions of Mobile Fetion,more important. |”;
2 levin108 @echo “| It\`s small and fast,and is better in look. |”;
2 levin108 @echo “| More information at http://basiccoder.com/openfetion |”;
2 levin108 @echo “———————————————————-”;

显示指定文件(本地的或者远程版本库中的)作者和修订版本信息。 当然看到这个命令的输出的时候才发现原来版本控制软件真的很强大。

svn log
example

$ svn log
————————————————————————
r11 | levin108 | 2010-04-06 19:31:11 +0800 | 1 行
4.5
————————————————————————
r10 | levin108 | 2010-04-06 18:49:41 +0800 | 1 行
test
————————————————————————
r9 | levin108 | 2010-04-06 18:49:18 +0800 | 1 行

显示提交日志信息。

svn status

打印工作拷贝文件和目录的状态,如A,D,U…详细如下:

A 添加
D 删除
U 更新
C 冲突
G 合并

svn list
example:

$ svn list https://ofetion.googlecode.com/svn/trunk/ –username levin108
AUTHORS
COPYING
ChangeLog
INSTALL
LICENSE

列出版本库目录的条目

svn update
example:

$svn update -r7

用版本号为7的版本库项目更新你的本地项目副本,不加-r就默认用最新的版本更新,这个命令很重要。

常用的命令差不多就这些了,其它不常用的我也记不住了,写一下以后自己忘了可以过来查

分类: Linux 标签: ,