思考充分再行动 – python试水记
这两天突发奇想觉得python脚本语言很简单,很实用,就一头扎入其中玩了几天,全然不顾还有一堆的工作等待我去crack。想起某人的话:“职业人与学生最大的差别在于兴趣的时候,是服从任务调遣还是内心。职业人只要有任务在身,deadline一旦设定就要努力向前,争取如期完成任务。而学生喜欢懒懒散散,尤其以兴趣来了为借口,东一榔头,西一榔头的瞎忙活,结果工期总是一推再推,比预计要花出多几倍的时间”。我目前就缺乏这种职业精神,原来做好的计划在变化和所谓兴趣面前烟消云散了。
在这里记录一下关于python试水的心得和过程。一方面是python试水手记,另一方面由于自己失误,犯了个大错误,因此这篇blog这也是对自己的一个提醒:因为在开始一个程序调试之前,很重要的一个因素:外部接口的支持程度,没有考虑到,导致瞎忙活了一天多时间,最后还没完成原始目标。
这两天在浏览时发现一个问题,有些pdf电子书没有做bookmark,不容易定位章节。网上有一个成熟的软件PdfBookmark可以根据一个xml文件生成pdf的书签。我就萌生用python写个脚本生成相应xml从而生成自己想要的书签的想法。
以后浏览书籍的过程是这样:
1. 浏览pdf书籍,手动记录章节和页码信息在一个excel或者txt文件中。
2. 用python读取这个简单的txt文件并按照规则生成PdfBookmark所需xml
3.用此xml更新pdf文件的bookmark
很简单的任务和目标,可惜自己之前没有调研软件PdfBookmark是否支持中文书签,实验了它的英文example,觉得很不错,就赶紧动手了。下面是整个实验试水的一个记录。
Setuptools 和 easyInstall的关系?
CPAN PyPI distutils eggs package management
setuptools是对python的package Index进行管理的工具,python工具包的后缀名都是.egg,需要专门的工具进行安装:easyInstall。
.egg 是windows平台上的二进制文件,可以直接被程序easyInstall调用。
目前的setuptools只能支持到python 2.6版本,而python3.1的setuptools没有官方版本。有网友开发出了可兼容python3的setuptools. http://regebro.wordpress.com/2009/02/01/setuptools-and-easy_install-for-python-3/
文章同时指出,当前支持3.1的python库还不多。不过距离当时发表时间已经过去1年了,不知目前的python 3.1的package库支持能力如何,应该有极大的提高和长进。就在1月4号,pyhon官方发布了最新的一批文档,更新频率还是挺快的。
lxm包的安装
1. 去http://codespeak.net/lxml/ ,下载lxml包。最新版本2.2.4,09年11月11日发布。
2. 然后根据instruction进行安装:http://codespeak.net/lxml/installation.html
3. 在此之前有两个依赖包。先不管。
4. 获取工具(也是基于python的一个功能模块)easy_install(Easy Install is a python module (easy_install) bundled with setuptools that lets you automatically download, build, install, and manage Python packages.)windows平台上,Pyhon 2.6版本会之间附带上easy_install.exe,但在3.1版本安装目录下,没有这个安装文件。而且,pyhon3.1没有easy_install工具。那么3.1如何安装更新包呢? 不解。
找到一封邮件回复说明python3.1暂不支持lxml,我就不想再花费时间去找新的工具解决这个big problem了。
Dov Reshef wrote:
> I’m trying to install lxml 2.2.2 for python 3.1. (I’m using the egg for
> python version 3, simply unpacking it to the site-packages folder). However,
> when I try to use it in my code I get “ImportError: DLL load failed”, which
> if I understand it correctly, means that it can’t find the etree.dll even
> though it’s right there in my site-packages folder (etree.pyd).
3.1 isn’t 3.0 compatible, I guess.
We don’t currently have binary eggs for 3.1, sorry.
5. 只能换到2.6平台,重新将上面的工作继续一遍.
C:\Documents and Settings\Administrator>easy_install
Easy_install 总是不能在其它目录下运行,明明将D:\Python26\Scripts;加入了path路径。后来发现D:\Python26\Scripts;必须在D:\Python26这个路径之后,系统才能将其识别。(这也是一个诡异的现象)
下载lxml-2.2.4-py2.4-win32.egg,然后运行安装程序:
C:\Documents and Settings\Administrator>easy_install C:\lxml-2.2.4-py2.4-win32.egg
终于将lxml装入python2.6的库中。
在文件夹:D:\Python26\Lib\site-packages 可以看到新增了lxml-2.2.4-py2.4-win32.egg文件夹以及一些新的文件。
在python 2.6运行cmd中,终于可以import lxml了
Python3中依然不能导入lxml,因为目前无法安装。
中文在读写xml文档中的问题
因为在写入中文时出现错误:
name = etree.SubElement(bookmark,’Name’)
name.text = “”+item[0]
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes
读取中文txt文件需要指定编码方式,否则open函数不知如何对字节进行解码为相应的字符。
发现windows平台上python默认的编码格式为:cp936,使用下面这个方法得到:
print(locale.getpreferredencoding())
在我的IDLE编辑器中,第一行有一句注释:# -*- coding: cp936 -*-
这个好像就是将.py文本的编码格式设定为cp936。让解释器对.py文件解释时识别其中的非ascii字符。我将其改成utf-8, getpreferredencoding输出的依然是cp936。
因为python2.6不支持open(‘’,encoding=’utf-8’)的语法,只好采用codecs包的open方法,但是用utf-8编码方式入读中文文件依然出现error。
import codecs
book_file = codecs.open(‘bookmark-logic.txt’,'r’)
File “D:\Python26\lib\encodings\utf_8.py”, line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: ‘utf8′ codec can’t decode bytes in position 0-1: invalid data
此时很明显是因为输入文件就不是用utf-8方式编码的。解决方法,用记事本将输入文件改成utf-8编码保存后即可。
但是又出现新问题,生成的文档无法正常显示中文。这是为何??当时以为问题肯定出在这一句:
中文显示有问题的xml片段
name.text = item[0] item的编码方式是utf-8,直接赋值给text,text可能会是unicode或者原始字符类型str,不一样。为何显示出来的unicode会是这种编码形式呢? text type is: <type 'unicode'> text type is: <type 'str'> item type is: <type 'unicode'> 经过找寻,发现不是name.text = item[0]的问题,而是在etree.tostring(root, encoding='utf-8', pretty_print=True) 少了对encoding的设置。设置后即可。 对item中的中文进行utf-8编码或者utf-8的解码均有问题,因为item[0]本身是unicode对象,不能再进行encode,但第二种情况,decode为何出现ordinal not in range(128) 的error??
![]()
Unicode编码与实际内容:
中文 46 1 基本原理 48 2 2.huise didai 53 2 unicode编码之后的实际字符为: [u'\ufeff\u4e2d\u6587\t46\t1\r', u'\u57fa\u672c\u539f\u7406\t48\t2\r', u'2.huise didai\t53\t2\r', u''] 在读入每一行字符后,用re.splite(‘\t’)函数得到具体内容,但是最后一个单词后面会跟一个看不见的\r\t, 而显示出来为 并且换行。我在如何读取时不读入这个符号这个问题上困扰了很久。最后发现可以之间将其去除.. <level>2 </level> 后来发现直接调用string的方法:(string.strip())即可去除这个换行符。题外话,
在这一次python3转2.6的过程中,发现语法差异还是不小: 比如2中不支持: #print('list display:{} {};'.format(count,item)) 在3之前的版本,print都不是一个函数。总结
到此为止,这个脚本基本能够搞定最初提出的生成相应xml的任务。可惜后来发现PdfBookmark无法识别unicode,还给他们公司发信询问了相关情况,确实目前版本不支持unicode,中文书签没法应用。这一次的任务无果而终,唯一收获是熟悉了python的相关细节如文件操作,xml解析等,并得到一个教训:做任务前要三思,考虑全面后方可行动!
For Setuptools support on Python 3, you can now use Distribute:
http://pypi.python.org/pypi/distribute