你不知道的 Python装饰器的一个妙用

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

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

我们来模拟一个场景,需要你去抓去一个页面,然后这个页面有好多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程序员的进化
责任编辑:陈贻新 来源: Vim
相关推荐

2019-11-25 14:05:47

Python装饰器数据

2014-01-22 16:19:06

游戏圈游戏创业移动游戏

2023-12-21 14:40:09

Python编程语言

2020-07-28 08:26:34

WebSocket浏览器

2020-06-12 09:20:33

前端Blob字符串

2010-08-23 09:56:09

Java性能监控

2019-08-09 14:20:46

微信软件手机

2018-04-26 13:33:20

Python语法Bug

2023-08-14 15:56:52

CSS 伪元素开发

2010-10-19 15:31:44

Java

2024-04-18 10:23:35

装饰器Python

2019-11-29 16:49:42

HTML语言开发

2015-09-16 10:48:57

Python

2021-01-05 11:22:58

Python字符串代码

2020-01-29 19:40:36

Python美好,一直在身边Line

2020-07-11 09:45:33

Python编程语言开发

2014-04-10 13:15:54

PythonPython技巧

2012-11-23 10:57:44

Shell

2015-06-19 13:54:49

2020-08-11 11:20:49

Linux命令使用技巧
点赞
收藏

51CTO技术栈公众号