Python爬虫(图片)编写过程中遇到的问题

  最近我突然对网络爬虫开窍了,真正做起来的时候发现并不算太难,都怪我以前有点懒,不过近两年编写了一些程序,手感积累了一些肯定也是因素,总之,还是惭愧了。好了,说正题,我把这两天做爬虫的过程中遇到的问题总结一下:

  需求:做一个爬虫,爬取一个网站上所有的图片(只爬大图,小图标就略过)

  思路:1、获取网站入口,这个入口网页上有很多图片集合入口,进入这些图片集合就能看到图片链接了,所以爬取的深度为2,比较简单;2、各个子图片集合内所包含的图片链接有两种形式:一种是绝对图片路径(直接下载即可),另一种的相对图片路径(需要自行拼接当前网页路径)。总之这些子图集合的表现形式简单,没有考虑更复杂的情况。3、在爬取的过程中保存已成功爬取的路径,防止每次爬取都执行重复的任务,当然,当每次启动时要首先加载该历史数据库,剩下的就是细节了。

  快速链接:

2.1 日志系统

2.2 记录访问历史

2.3 异常处理

2.4 网页自动编码判断

2.5 远程主机重置链接(Errno 10054)

一、全部代码

  直接先来代码,再详细说优化的过程和内容吧:

  1 __author__ = ‘KLH‘
  2 # -*- coding:utf-8 -*-
  3
  4 import urllib
  5 import urllib2
  6 import chardet
  7 import re
  8 import os
  9 import time
 10 from myLogger import *
 11
 12 # 网络蜘蛛
 13 class Spider:
 14
 15     # 类初始化
 16     def __init__(self):
 17         self.contentFolder = u"抓取内容"
 18         self.dbName = "url.db"
 19         self.createFolder(self.contentFolder)
 20         self.urlDB = set()
 21
 22     # 获取URL数据库以获取爬过的网页地址
 23     def loadDatabase(self):
 24         isExists = os.path.exists(self.dbName)
 25         if not isExists:
 26             logging.info(u"创建URL数据库文件:‘" + self.dbName + u"‘")
 27             f = open(self.dbName, ‘w+‘)
 28             f.write("#Create time: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) + ‘\n‘)
 29             f.close()
 30             return
 31         db = open(self.dbName, ‘r‘)
 32         for line in db.readlines():
 33             if not line.startswith(‘#‘):
 34                 self.urlDB.add(line.strip(‘\n‘))
 35         db.close()
 36         logging.info(u"URL数据库加载完成!")
 37
 38     # 追加数据库文件
 39     def writeToDatabase(self, url):
 40         db = open(self.dbName, ‘a‘)
 41         db.write(url + ‘\n‘)
 42         db.close()
 43
 44     # 处理路径名称中的空格字符
 45     def getPathName(self, pathName):
 46         newName = ""
 47         subName = pathName.split()
 48         i = 0
 49         while i < len(subName) - 1:
 50             newName = newName + subName[i]
 51             i = i + 1
 52         return newName
 53
 54     # 获取索引页面的内容
 55     def getPage(self, pageURL, second):
 56         try:
 57             headers = {‘User-agent‘ : ‘Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0‘}
 58             request = urllib2.Request(pageURL, headers = headers)
 59             response = urllib2.urlopen(request, timeout = second)
 60             data = response.read()
 61             response.close()
 62             return data.decode(‘gbk‘), True
 63         except urllib2.HTTPError,e:    #HTTPError必须排在URLError的前面
 64             logging.error("HTTPError code:" + str(e.code) + " - Content:" + e.read())
 65             return "", False
 66         except urllib2.URLError, e:
 67             logging.error("URLError reason:" + str(e.reason) + " - " + str(e))
 68             return "", False
 69         except Exception, e:
 70             logging.error(u"获取网页失败:" + str(e))
 71             return "", False
 72
 73     # 获取索引界面所有子页面信息,list格式
 74     def getContents(self, pageURL, second):
 75         contents = []
 76         page, succeed = self.getPage(pageURL, second)
 77         if succeed:
 78             # 这里的正则表达式很重要,决定了第一步的抓取内容:
 79             pattern = re.compile(‘<tr>.*?<a href="(.*?)".*?<b>(.*?)</b>.*?</tr>‘,re.S)
 80             items = re.findall(pattern,page)
 81             for item in items:
 82                 contents.append([item[0],item[1]])
 83         contents.sort()
 84         return contents
 85
 86     # 获取页面所有图片
 87     def getAllImgURL(self, infoURL):
 88         images = []
 89         succeed = True
 90         try:
 91             headers = {‘User-agent‘ : ‘Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0‘}
 92             request = urllib2.Request(infoURL, headers = headers)
 93             data = urllib2.urlopen(request).read()
 94             chardet1 = chardet.detect(data)     # 自动判断网页编码
 95             page = data.decode(str(chardet1[‘encoding‘]))
 96
 97             # 第一种解码格式:
 98             pattern = re.compile(‘<option value="(.*?)">(.*?)</option>‘)
 99             items = re.findall(pattern, page)
100             # item[0]为图片URL尾部,item[1]为图片名称
101             for item in items:
102                 if item.startswith(‘http://‘):
103                     imageURL = item[0]
104                     if imageURL in self.urlDB:
105                         logging.info(u"获得图片URL(曾被访问,跳过):" + imageURL)
106                     else:
107                         logging.info(u"获得图片URL:" + imageURL)
108                         images.append(imageURL)
109                 else:
110                     imageURL = infoURL + item[0]
111                     if imageURL in self.urlDB:
112                         logging.info(u"获得图片URL(曾被访问,跳过):" + imageURL)
113                     else:
114                         logging.info(u"获得图片URL:" + imageURL)
115                         images.append(imageURL)
116
117             # 第二种解码格式
118             pattern = re.compile(‘<IMG src="(.*?)".*?>‘)
119             items = re.findall(pattern, page)
120             # item为图片URL
121             for item in items:
122                 if item.startswith(‘http://‘):
123                     if item in self.urlDB:
124                         logging.info(u"获得图片URL(曾被访问,跳过):" + item)
125                     else:
126                         logging.info(u"获得图片URL:" + item)
127                         images.append(item)
128
129         except Exception, e:
130             logging.warning(u"在获取子路径图片列表时出现异常:" + str(e))
131             succeed = False
132         return images, succeed
133
134     # 保存所有图片
135     def saveImgs(self, images, name):
136         logging.info(u‘发现"‘ + name + u‘"共有‘ + str(len(images)) + u"张照片")
137         allSucceed = True
138         for imageURL in images:
139             splitPath = imageURL.split(‘/‘)
140             fTail = splitPath.pop()
141             fileName = name + "/" + fTail
142             logging.info(u"开始准备保存图片(超时设置:120秒):" + imageURL)
143             startTime = time.time()
144             succeed = self.saveImg(imageURL, fileName, 120)
145             spanTime = time.time() - startTime
146             if succeed:
147                 logging.info(u"保存图片完成(耗时:" + str(spanTime) + u"秒):" + fileName)
148                 # 保存文件存储记录
149                 self.urlDB.add(imageURL)
150                 self.writeToDatabase(imageURL)
151             else:
152                 logging.warning(u"保存图片失败(耗时:" + str(spanTime) + u"秒):" + imageURL)
153                 allSucceed = False
154             # 为了防止网站封杀,这里暂停1秒
155             time.sleep(1)
156         return allSucceed
157
158     # 传入图片地址,文件名,超时时间,保存单张图片
159     def saveImg(self, imageURL, fileName, second):
160         try:
161             headers = {‘User-agent‘ : ‘Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0‘}
162             request = urllib2.Request(imageURL, headers = headers)
163             u = urllib2.urlopen(request, timeout = second)
164             data = u.read()
165             f = open(fileName, ‘wb‘)
166             f.write(data)
167             f.close()
168             u.close()
169             return True
170         except urllib2.HTTPError,e:    #HTTPError必须排在URLError的前面
171             logging.error("HTTPError code:" + str(e.code) + " - Content:" + e.read())
172             return False
173         except urllib2.URLError, e:
174             logging.error("URLError reason:" + str(e.reason) + " - " + str(e))
175             return False
176         except Exception, e:
177             logging.error(u"保存图片失败:" + str(e))
178             return False
179
180     # 创建新目录
181     def createFolder(self, path):
182         path = path.strip()
183         # 判断路径是否存在
184         isExists=os.path.exists(path)
185         # 判断结果
186         if not isExists:
187             # 如果不存在则创建目录
188             logging.info(u"创建文件夹:‘" + path + u"‘")
189             # 创建目录操作函数
190             os.makedirs(path)
191             return True
192         else:
193             # 如果目录存在则不创建,并提示目录已存在
194             logging.info(u"名为‘" + path + u"‘的文件夹已经存在,跳过")
195             return False
196
197     # 获取的首页地址
198     def savePageInfo(self, pageURL):
199         logging.info(u"准备获取网页内容(超时设置:60秒):" + pageURL)
200         contents = self.getContents(pageURL, 60)
201         logging.info(u"网页内容获取完成,子路径个数:" + str(len(contents)))
202         index = 1
203         for item in contents:
204             #(1)item[0]子路径URL, item[1]子路径名称
205             folderURL = item[0]
206             folderName = self.contentFolder + ‘\\‘ + str(index) + "-" + self.getPathName(item[1])
207             self.createFolder(folderName)
208             index = index + 1
209
210             #(2)判断链接头部合法性和重复性
211             if not folderURL.startswith(‘http://‘):
212                 folderURL = pageURL + folderURL
213             if folderURL in self.urlDB:
214                 logging.info(u‘"‘ + folderName + u‘"的链接地址(已访问,跳过)为:‘ + folderURL)
215                 continue
216             else:
217                 logging.info(u‘"‘ + folderName + u‘"的链接地址为:‘ + folderURL)
218
219             #(3)获取图片URL列表,成功则保存图片
220             images, succeed = self.getAllImgURL(folderURL)
221             if succeed:
222                 succeed = self.saveImgs(images, folderName)
223                 if succeed:
224                     self.urlDB.add(folderURL)
225                     self.writeToDatabase(folderURL)
226
227 # 初始化系统日志存储
228 InitLogger()
229 # 传入初始网页地址,自动启动爬取图片:
230 spider = Spider()
231 spider.loadDatabase()
232 spider.savePageInfo(‘http://365.tw6000.com/xtu/‘)
233 logging.info(u"全部网页内容爬取完成!程序退出。")

查看全部代码

二、问题历史

  在上面的代码中有不少的细节是优化解决过的,相关的知识点如下:

2.1 日志系统

  Python的日志系统是相当的不错,非常的方便,详细的资料可以参考Python官方文档,或者上一篇博文也是提到过的:《Python中的日志管理Logging模块》,应用到我这个爬虫这里的代码就是myLogger.py模块了,用起来很方便:

 1 __author__ = ‘KLH‘
 2 # -*- coding:utf-8 -*-
 3
 4 import logging
 5 import time
 6
 7 def InitLogger():
 8     logFileName = ‘log_‘ + time.strftime("%Y%m%d%H%M%S", time.localtime(time.time())) + ‘.txt‘
 9     logging.basicConfig(level=logging.DEBUG,
10                         format=‘[%(asctime)s][%(filename)s:%(lineno)d][%(levelname)s] - %(message)s‘,
11                         filename=logFileName,
12                         filemode=‘w‘)
13
14     # 定义一个StreamHandler将INFO级别以上的信息打印到控制台
15     console = logging.StreamHandler()
16     console.setLevel(logging.INFO)
17     formatter = logging.Formatter(‘[%(asctime)s][%(filename)s:%(lineno)d][%(levelname)s] - %(message)s‘)
18     console.setFormatter(formatter)
19     logging.getLogger(‘‘).addHandler(console)

查看myLogger.py

  注意在爬虫的代码执行前调用一下该函数:

from myLogger import *# 初始化系统日志存储
InitLogger() 

  日志调用和打印的结果如下:

logging.info(u"准备获取网页内容(超时设置:60秒):" + pageURL)

#打印结果如下:
[2015-11-09 22:35:02,976][spider2.py:182][INFO] - 准备获取网页内容(超时设置:60秒):http://365.XXXXX.com/xtu/

2.2 记录访问历史

  这里记录URL的访问历史是为了防止执行重复任务,在内存中保持一个Set就能满足需求,在磁盘上可以简单的保存成一个TXT文件,每个URL保存成一行即可。所以这里是逻辑顺序应该是在初始化时创建一个Set用来保存访问历史,任务执行之前从数据库中加载访问历史,如果是首次运行尚未创建数据库还需要进行一次创建操作。然后就好办了,每次完成一个URL的访问就保存一下访问记录。相关代码如下:

 1 # 类初始化
 2 def __init__(self):
 3     self.contentFolder = u"抓取内容"
 4     self.dbName = "url.db"              # 1、定义数据库文件名
 5     self.createFolder(self.contentFolder)   # 2、创建内容存储目录
 6     self.urlDB = set()                # 3、创建内存数据库
 7
 8 # 获取URL数据库以获取爬过的网页地址
 9 def loadDatabase(self):
10     isExists = os.path.exists(self.dbName)  # 4、首先判断是否是首次运行,如果数据库文件不存在则创建一下
11     if not isExists:
12         logging.info(u"创建URL数据库文件:‘" + self.dbName + u"‘")
13         f = open(self.dbName, ‘w+‘)
14         f.write("#Create time: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) + ‘\n‘)
15         f.close()
16         return
17     db = open(self.dbName, ‘r‘)         # 5、从磁盘中加载数据库
18     for line in db.readlines():
19         if not line.startswith(‘#‘):
20             self.urlDB.add(line.strip(‘\n‘))
21     db.close()
22     logging.info(u"URL数据库加载完成!")
23
24 # 追加数据库文件
25 def writeToDatabase(self, url):         # 6、在系统运行过程中,如需记录日志,追加日志内容即可
26     db = open(self.dbName, ‘a‘)
27     db.write(url + ‘\n‘)
28     db.close()

  有了上面的代码,在记录日志过程中就很方便了:

succeed = self.saveImgs(images, folderName)
    if succeed:
        self.urlDB.add(folderURL)
        self.writeToDatabase(folderURL)

2.3 异常处理

  访问网络资源不可避免的会有很多异常情况,要处理这些异常情况才能稳定运行,Python的异常处理很简单,请参考如下获取网页的代码段:

 1 # 获取索引页面的内容
 2 def getPage(self, pageURL, second):
 3     try:
 4         request = urllib2.Request(pageURL)
 5         response = urllib2.urlopen(request, timeout = second)
 6         data = response.read()
 7         return data.decode(‘gbk‘), True
 8     except urllib2.HTTPError,e:    # HTTPError必须排在URLError的前面
 9         logging.error("HTTPError code:" + str(e.code) + " - Content:" + e.read())
10         return "", False
11     except urllib2.URLError, e:
12         logging.error("URLError reason:" + str(e.reason) + " - " + str(e))
13         return "", False
14     except Exception, e:       # 其他所有类型的异常
15         logging.error(u"获取网页失败:" + str(e))
16         return "", False       # 这里返回两个值方便判断

2.4 网页自动编码判断

  昨天在爬取网页的过程中突然发现,有的页面居然说编码不能通过utf-8进行解析,我看了看有的网页确实不是utf-8编码的,那怎么办呢?怎么才能自动进行解码?从网上可以搜索到一个Python的开源库很好用,叫做chardet,默认Python2.7是不带的需要下载,比如我下载的是:chardet-2.3.0.tar.gz

  有了这个压缩包解压出来cahrdet子文件夹拷贝到:C:\Python27\Lib\site-packages目录下即可。下面看看用法实例:

 1 import chardet
 2
 3 # 获取页面所有图片
 4 def getAllImgURL(self, infoURL):
 5   images = []
 6   succeed = True
 7   try:
 8     data = urllib2.urlopen(infoURL).read()  # 1、先获取网页内容
 9     chardet1 = chardet.detect(data)        # 2、再调用该模块的方法自动判断网页编码
10     page = data.decode(str(chardet1[‘encoding‘]))   # 3、注意,得到的chardet1是一个字典类似于:{‘confidence‘: 0.98999999999999999, ‘encoding‘: ‘GB2312‘}
11
12     # 第一种解码格式:
13     pattern = re.compile(‘<option value="(.*?)">(.*?)</option>‘)
14     items = re.findall(pattern, page)
15     # item[0]为图片URL尾部,item[1]为图片名称
16     for item in items:
17       imageURL = infoURL + item[0]
18       if imageURL in self.urlDB:
19         logging.info(u"获得图片URL(曾被访问,跳过):" + imageURL)
20       else:
21         logging.info(u"获得图片URL:" + imageURL)
22         images.append(imageURL)
23
24     # 第二种解码格式
25     pattern = re.compile(‘<IMG src="(.*?)".*?>‘)
26     items = re.findall(pattern, page)
27     # item为图片URL
28     for item in items:
29       if item.startswith(‘http://‘):    # 4、这里也注意一下,在这种网页中相对路径的图片都是插图之类的小图片不需要下载,所以过滤掉了。
30         if item in self.urlDB:
31             logging.info(u"获得图片URL(曾被访问,跳过):" + item)
32         else:
33           logging.info(u"获得图片URL:" + item)
34           images.append(item)
35
36   except Exception, e:
37     logging.warning(u"在获取子路径图片列表时出现异常:" + str(e))
38     succeed = False
39   return images, succeed

2.5 远程主机重置链接(Errno 10054)

  在今天的爬取过程中我发现了一个问题,爬到后面的内容都出错了,错误信息参见如下:

[2015-11-09 23:48:51,082][spider2.py:130][INFO] - 开始准备保存图片(超时设置:300秒):http://xz1.XXXX.com/st/st-06/images/009.jpg
[2015-11-09 23:48:55,095][spider2.py:160][ERROR] - 保存图片失败:[Errno 10054]
[2015-11-09 23:48:55,096][spider2.py:140][WARNING] - 保存图片失败(耗时:4.01399993896秒):http://xz1.XXXX.com/st/st-06/images/009.jpg
[2015-11-09 23:48:55,098][spider2.py:130][INFO] - 开始准备保存图片(超时设置:300秒):http://xz1.XXXX.com/st/st-06/images/010.jpg
[2015-11-09 23:48:56,576][spider2.py:160][ERROR] - 保存图片失败:[Errno 10054]
[2015-11-09 23:48:56,578][spider2.py:140][WARNING] - 保存图片失败(耗时:1.48000001907秒):http://xz1.XXXX.com/st/st-06/images/010.jpg

  可以看到都在报这个错误代码,网上一查,发现有很多同学已经遇到过了,请参考知乎上的讨论:http://www.zhihu.com/question/27248551

  从网上讨论的结果来看,可以肯定的是直接原因在于“远程主机主动关闭了当前链接”,而根本原因则在于:网站启用了反爬虫的策略,也就是说我的爬虫爬的过快并且被发现不是真正的浏览器浏览了。怎么办了?针对这两个原因逐个处理,一是伪装成浏览器,二是不要访问的过快,三是每次访问完成都关闭链接。相关代码如下:

 1 # 传入图片地址,文件名,超时时间,保存单张图片
 2 def saveImg(self, imageURL, fileName, second):
 3   try:
 4     headers = {‘User-agent‘ : ‘Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0‘}  # 1、这里构造一个浏览器的头部
 5     request = urllib2.Request(imageURL, headers = headers)
 6     u = urllib2.urlopen(request, timeout = second)     # 2、这里的超时设置timeout不要太长
 7     data = u.read()
 8     f = open(fileName, ‘wb‘)
 9     f.write(data)
10     f.close()
11     u.close()    # 3、注意这里的链接要主动调用一下关闭
12     return True
13   except urllib2.HTTPError,e:    #HTTPError必须排在URLError的前面
14     logging.error("HTTPError code:" + str(e.code) + " - Content:" + e.read())
15     return False
16   except urllib2.URLError, e:
17     logging.error("URLError reason:" + str(e.reason) + " - " + str(e))
18     return False
19   except Exception, e:
20     logging.error(u"保存图片失败:" + str(e))
21     return False  # 4、注意调用完这个函数之后再time.sleep(1)一下,防止过快访问被发现了,呵呵
时间: 2024-10-12 20:50:05

Python爬虫(图片)编写过程中遇到的问题的相关文章

Selenium2学习-018-WebUI自动化实战实例-016-自动化脚本编写过程中的登录验证码问题

日常的 Web 网站开发的过程中,为提升登录安全或防止用户通过脚本进行黄牛操作(宇宙最贵铁皮天朝魔都的机动车牌照竞拍中),很多网站在登录的时候,添加了验证码验证,而且验证码的实现越来越复杂,对其进行脚本识别的难度也越来越高.这对我们自动化脚本编写带了非常的不便,那么如何解决登录时的验证码问题呢?经常有初学自动化脚本编写的小主们问及此问题. 此文主要针对如何解决自动化测试脚本中含登录态的操作问题,即如何降低验证码对自动化脚本编写过程中的解决方法进行分析和解决,并以实例演示(基于易迅网易迅账号登录)

ABAP程序编写过程中怎么提高程序执行效率一

影响ABAP程序的运行效率主要是在程序中大量数据的取得,如果取数不得方法,很影响报表的运行效率,所有优化ABAP程序主要是优化数据取数的方法.下面这几点可以有效的提高取数的效率,从而来提高程序的运行效率. 1.选择最有效率的表名顺序(只在基于规则的优化器中有效): ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 drivingtable)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.如果有3个以上的表连

scrapy爬虫编写过程中的小技巧

小工具: 关于网页代码中意向信息的查找可以借助几个工具: 第一个——Firefox插件Firebug. 第二个——Firefox插件XPath.可以快速的在网页中对xpath表达式的正确性进行验证. 第三个——scrapy shell.关于其使用可以查看教程.

第一次写,python爬虫图片,操作excel。

第一次写博客,其实老早就注册博客园了,有写博客的想法,就是没有行动,总是学了忘,忘了丢,最后啥都没有,电脑里零零散散,东找找,西看看,今天认识到写博客的重要性. 最近闲着看了潭州教育的在线直播课程,颇受老师讲课实用有感.只作为自己笔记学习,我们都知道学习一门编程都是先照抄,在创作.这里完全按照老师讲解,照抄作为学习. 一.Python抓取豆瓣妹子图. 工具:python3.6.0;bs4.6.0;xlwt(1.2.0)需要版本对应,之前就安装了bs4但是运行的时候提示版本不对应.可以在线升级:p

python爬虫之Scrapy框架中的Item Pipeline用法

当Item在Spider中被收集之后, 就会被传递到Item Pipeline中进行处理. 每个item pipeline组件是实现了简单的方法的python类, 负责接收到item并通过它执行一些行为, 同时也决定此item是否继续通过pipeline, 或者被丢弃而不再进行处理. item pipeline的主要作用 : 1. 清理html数据 2. 验证爬取的数据 3. 去重并丢弃 4. 将爬取的结果保存到数据库中或文件中 编写自己的item pipeline : process_item

Python 爬虫-图片的爬取

2017-07-25 22:49:21 import requests import os url = 'https://wallpapers.wallhaven.cc/wallpapers/full/wallhaven-278989.jpg' root = 'E://pics//' path = root + url.split('/')[-1] def gethtml(url): # 打开网页有风险,需要使用try-except语句进行风险控制 kv = {'user-agent':'Chr

python模拟websocket握手过程中计算sec-websocket-accept

背景 以前,很多网站使用轮询实现推送技术.轮询是在特定的的时间间隔(比如1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给浏览器.轮询的缺点很明显,浏览器需要不断的向服务器发出请求,然而HTTP请求的header是非常长 的,而实际传输的数据可能很小,这就造成了带宽和服务器资源的浪费. Comet使用了AJAX改进了轮询,可以实现双向通信.但是Comet依然需要发出请求,而且在Comet中,普遍采用了长链接,这也会大量消耗服务器带宽和资源. 于是,WebSocke

解决jsp编写过程中换另一个jsp可以忽视登录过程

在编写web大作业时发现,如果直接更换jsp地址,可以直接进入管理员界面. 为了解决这一问题,首先编写一个check文档: <% HttpSession sessi= request.getSession(); String login = (String) sessi.getAttribute("login"); if( !"login".equals(login)){ request.setAttribute("err","未

Python - 装饰器使用过程中的误区

装饰器基本概念 大家都知道装饰器是一个很著名的设计模式,经常被用于AOP(面向切面编程)的场景,较为经典的有插入日志,性能测试,事务处理,Web权限校验, Cache等. Python语言本身提供了装饰器语法(@),典型的装饰器实现如下: @function_wrapper def function(): pass @实际上是python2.4才提出的语法糖,针对python2.4以前的版本有另一种等价的实现: def function(): pass function = function_w