技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 其他 --> Tweets2PDF开发手记

Tweets2PDF开发手记

浏览:1706次  出处信息

之前一直想学一下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问题太多了,不搞了,还是等有兴趣有经验的牛人来搞吧。

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

QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1