你不知道的 Python装饰器的一个妙用
创始人
2024-07-24 21:40:50
0

好吧,我知道是大半夜……,但我还是觉得赶紧花上半个小时,把这最新的想法分享出来是值得的~直接进入正题~

我们来模拟一个场景,需要你去抓去一个页面,然后这个页面有好多url也要分别去抓取,而进入这些子url后,还有数据要抓取。简单点,我们就按照三层来看,那我们的代码就是如下:

  1. def func_top(url):  
  2.     data_dict= {}  
  3.    
  4.     #在页面上获取到子url  
  5.     sub_urls = xxxx  
  6.    
  7.     data_list = []  
  8.     for it in sub_urls:  
  9.         data_list.append(func_sub(it))  
  10.    
  11.     data_dict['data'] = data_list  
  12.    
  13.     return data_dict  
  14.    
  15. def func_sub(url):  
  16.     data_dict= {}  
  17.    
  18.     #在页面上获取到子url  
  19.     bottom_urls = xxxx  
  20.    
  21.     data_list = []  
  22.     for it in bottom_urls:  
  23.         data_list.append(func_bottom(it))  
  24.    
  25.     data_dict['data'] = data_list  
  26.    
  27.     return data_dict  
  28.    
  29. def func_bottom(url):  
  30.     #获取数据  
  31.     data = xxxx  
  32.     return data 

func_top是上层页面的处理函数,func_sub是子页面的处理函数,func_bottom是最深层页面的处理函数,func_top会在取到子页面url后遍历调用func_sub,func_sub也是同样。

如果正常情况下,这样确实已经满足需求了,但是偏偏这个你要抓取的网站可能极不稳定,经常链接不上,导致数据拿不到。

于是这个时候你有两个选择:

◆ 1. 遇到错误就停止,之后重新从断掉的位置开始重新跑

◆ 2. 遇到错误继续,但是要在之后重新跑一遍,这个时候已经有的数据不希望再去网站拉一次,而只去拉没有取到的数据

对第一种方案基本无法实现,因为如果别人网站的url调整顺序,那么你记录的位置就无效了。那么只有第二种方案,说白了,就是要把已经拿到的数据cache下来,等需要的时候,直接从cache里面取。

OK,目标已经有了,怎么实现呢?

如果是在C++中的,这是个很麻烦的事情,而且写出来的代码必定丑陋无比,然而庆幸的是,我们用的是Python,而Python对函数有装饰器。

所以实现方案也就有了:

定义一个装饰器,如果之前取到数据,就直接取cache的数据;如果之前没有取到,那么就从网站拉取,并且存入cache中.

代码如下:

  1. def get_dump_data(dir_name, url):  
  2.     m = hashlib.md5(url)  
  3.     filename = m.hexdigest()  
  4.     full_file_name = 'dumps/%s/%s' % (dir_name,filename)  
  5.    
  6.     if os.path.isfile(full_file_name):  
  7.         return eval(file(full_file_name,'r').read())  
  8.     else:  
  9.         return None 
  10.    
  11.    
  12. def set_dump_data(dir_name, url, data):  
  13.     if not os.path.isdir('dumps/'+dir_name):  
  14.         os.makedirs('dumps/'+dir_name)  
  15.    
  16.     m = hashlib.md5(url)  
  17.     filename = m.hexdigest()  
  18.     full_file_name = 'dumps/%s/%s' % (dir_name,filename)  
  19.    
  20.     f = file(full_file_name, 'w+')  
  21.     f.write(repr(data))  
  22.     f.close()  
  23.    
  24.    
  25. def deco_dump_data(func):  
  26.     def func_wrapper(url):  
  27.         data = get_dump_data(func.__name__,url)  
  28.         if data is not None:  
  29.             return data  
  30.    
  31.         data = func(url)  
  32.         if data is not None:  
  33.             set_dump_data(func.__name__,url,data)  
  34.         return data  
  35.    
  36.     return func_wrapper 

然后,我们只需要在每个func_top,func_sub,func_bottom都加上deco_dump_data这个装饰器即可~~

搞定!这样做最大的好处在于,因为top,sub,bottom,每一层都会dump数据,所以比如某个sub层数据dump之后,是根本不会走到他所对应的bottom层的,减少了大量的开销!

OK,就这样~ 人生苦短,我用Python!

原文链接:http://www.vimer.cn/2011/04/python%E8%A3%85%E9%A5%B0%E5%99%A8%E7%9A%84%E4%B8%80%E4%B8%AA%E5%A6%99%E7%94%A8.html

【编辑推荐】

  1. Python编辑利器:PyCharm初探
  2. 浅析Python中的列表解析和生成表达式
  3. 自制Python函数帮助查询小工具
  4. 巧用IronPython做更灵活的网页爬虫
  5. 一个Python程序员的进化

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...