本人在用GAE写爬虫的时候,遇到判断重复URL来防止重复抓取的问题,但是由于GAE数据库的限制(db.ListProperty每个记录不能保存超过5000个元素),经测试发现直接筛选数据库中的属性来判断是否有重复链接 会耗费大量CPU时间(甚至有时候会花费0.3秒来判断是否已经抓过某个网页),而利用建立哈希表来解决也没有多少改善.
经分析,根本问题在于hash颗粒度太小,读取数据库时使用GQL难免会比 (url in list)这样的python内置语句慢.经过查阅相关资料,用memcache可以解决.因为memcache是保存在内存中的,所以它的效率很高,且不随请求完毕而消亡.但是memcache有1M大小的限制,而且它并不是永久持久化的.可能因为服务器原因而丢失老数据.
有另一种解决方案就是把hash_list存到一个包装好的raw数据包中,put到数据库,下次使用再展开...于是我找到了marshal模块.它有将python所有内置数据类型和数据结构打包的功能.
注:另外一个python持久化的模块叫pickle 还有其C的底层实现:cPickle,与marshal模块不同的是,它可以记录自定义模块的数据.且展开时要导入原来的模块,若导入失败会引发一个异常.
利用python的marshal内置模块构建dump
以下是判断是否存在url记录的方法:
此方法用time测试 每个in 判断的操作需要时间小于0.001s
hash的list空间占用还是很小的,以每个数据记录为2M,每个hash数位64位(8字节)整形,打包不浪费空间,这样计算的话,能记录2*1024^3 /8 = 268435456 条hash数据
等空间不够时,还可以用zlib压缩一下,经过测试可以变成大小的1/3到1/4 ,证明marshal打包后 压缩空间还是蛮大的 毕竟全部是hash数组成的list
再多的数据便要有更多的Dump项来实现了.
但是这个方法也不是很高效,因为每次还要抓一下数据库或者这个包,希望懂GAE的大侠指正或建议.