先说句题外话:制定一个目标,在千回百转揪落一地头发后完成它,有点意思。
言归正传,俗话说,有人的地方就有江湖,而有江湖的地方就有需求。比如客户要在CRM做跨对象的数据迁移,并且原对象下有不少文档。因此,两点需求:
数据迁移
数据下文档迁移
数据迁移比较简单,代码或者简单的数据导出、清洗再导入都行。由于系统不支持文档与数据的重新关联,所以处理起来麻烦些,大体有两种方案:
利用系统批量下载功能,先下载到本地,然后对照原数据与文档关联关系再重新上传到新的数据下
通过脚本自动下载再上传
方案一明显工作量巨大,方案二可以通过java实现,这次我们选择了一时风头无两的python吃螃蟹,有点麻烦,但架不住有营养。
实现的整体思路是:
根据新对象里的数据匹配到原对象数据
查出原对象下文档并下载到本地
上传文档到服务器
将文档关联到新对象
标记新对象下数据处理状态
其实需求和实现逻辑都比较简单,下面主要说下实现方式、遇到的问题和解决方案。
调REST接口用的是第三方的requests库
文件下载。下载时requests指定了stream=True,并通过字节写入文件
文件上传是遇到问题最多的地方,直接导致两天茶饭不思。主要有:
1)文件名只能识别英文,不能识别中文
2)文件名能识别中文,上传也成功了,但文件内容丢失了
3)文件内容上传成功了,但中文文件名变成了字节码,系统不能识别
google+百度了很多种方法(相关链接在文末),试了都是在上面三种问题中打转。所谓尽信书则不如无书,诚不我欺。下面是最终代码:
说明:
1)在传files参数时,需要在元祖中指定"multipart/form-data"
2)post中要传递files参数,如果有额外数据可以用data,我们接口不需要
3)post参数中不能指定流方式,即stream=True,否则文件编码是字节码
4)需要修改当前项目路径Lib\site-packages\urllib3下的fields.py模块中的参数:
a. 注释掉第45行的:value = email.utils.encode_rfc2231(value, 'utf-8')
b. 将第46行的:value = '%s*=%s' % (name, value) 修改为 value = '%s="%s"' % (name, value)。网上很多解决方法说的是修改为:value = '%s="%s"' % (name, value.decode("utf-8")),但实际操作中这样会报错:str没有decode方法,然后改成encode("utf-8"),相当于把文件名加密,这样导致了上面说的第三个问题。后来觉得是加了编码的问题就直接把编码去掉了就可行了。其实这部分对原理还不是很清楚,后面再研究。所以有人说编码问题迟早会遇到,不彻底解决会haunt你的程序人生,还是有道理的。
Errno 10054。在做文件上传下载时还遇到了10054错误,是因为服务器认为频繁的下载上传是攻击,所以终止了客户端的请求。做爬虫爬取网页时也有遇到。解决方法是request完睡一会儿就行,机器还是很好骗的。
说完需求再夹带点私货说说python吧。当然,我才刚能写几句代码,理解可能不深入:
简单易上手。打开cmd就能编程,不用关心IDE怎么用,开始就能用turtle画了个五角星;
代码简洁但规范。开始从java换过来还不适应,老觉得变量前面不加个类型咋整啊,js好歹有var撑撑门面,new都不new就开怼,不加分号说变道就变道,感觉就是卸下法律与道德的枷锁,天高任鸟飞。但另一方面要求又很严,缩进四个空格不说了,变量命名不能用camel得用下划线,方法定义前必须空一行且仅是一行,类前后必须空两行且仅是两行,否则虽然不报错,但淡绿色的下划线膈应得让人想把星座改了。习惯就好;
学习资源少。python免费的教程连类不讲,django免费的基本就走个过场,所以自学不够友好;
封装向左,原理向右。封装程度越高,用户只要会用就行了,对新入门的人来说就比较少接触到底层原理,对机制的了解就弱一些,第三方库出现问题时排错就越难。个人觉得像javaweb那样先学HttpServlet再用SpringMVC会比较好。
最后,让我们高呼:人生苦短,_ _ _ _。
封面图来自:pixabay.com
领取专属 10元无门槛券
私享最新 技术干货