记性不好,又是学习新东西,自己写给自己看吧,有时间再详细弄弄。
声明一遍:这个是站内的开源爬虫程序urlwatch1.7~~
程序没有跑过,先把源码下下来学习了,接触到了distutils、optparse,又巩固了下os.path。
urlwatch文件用python写成,不过没有加py后缀。
前面都是一些说明和变量注释,从53行开始,把一些常用的方法于函数过了一遍。
# os.path.expanduser调用后,返回的urlwatch_dir就是~/urlwatcher目录
# 通过调用join方法可以使得路径的分隔符不受系统限制,win上是'\',unix是'/'
53 urlwatch_dir = os.path.expanduser(os.path.join('~', '.'+pkgname))
54 urls_txt = os.path.join(urlwatch_dir, 'urls.txt')
55 cache_dir = os.path.join(urlwatch_dir, 'cache')
56 scripts_dir = os.path.join(urlwatch_dir, 'lib')
57 hooks_py = os.path.join(scripts_dir, 'hooks.py')
58
# sys.argv[0]传入的脚本名称
# os.path.abspath取脚本的绝对路径
# os.path.dirname取除去文件名后的目录名
# os.path.split分隔文件名和目录名,用个tuple来装,bindir是末尾的文件目录
59 # Check if we are installed in the system already
60 (prefix, bindir) = os.path.split(os.path.dirname(os.path.abspath(sys.argv[0])))
# sys.path.append是将目录加入python系统目录,使其能够访问lib目录里的文件
68 sys.path.append(os.path.join(prefix, bindir, 'lib'))
# logging日志模块
# 设置日志级别
94 log = logging.getLogger(pkgname)
95 log.setLevel(logging.DEBUG)
# 添加空handler,不知有什么用,待查
101 log.addHandler(NullHandler())
# 在type.upper()和url之间插入“:“
114 summary_txt = ': '.join((type.upper(), url))
# main开始
130 if __name__ == '__main__':
# 取当前系统时间
131 start = datetime.datetime.now()
再接下来就是郁闷我很久的optparse
# 先出个OptionParser,附上说明
134 parser = optparse.OptionParser(usage='%%prog [options]\n\n%s' % __doc__. strip(), version=pkgname+' '+__version__)
# 如果出现传入参数-v,等价于options.verbose=true
135 parser.add_option('-v', '--verbose', action='store_true', dest='verbose' , help='Show debug/log output')
# 出现传入参数--urls, 等价于options.urls为--urls后紧跟的参数
# metavar有助于提醒用户,该命令行参数所期待的参数,如 metavar="mode"(找了很久都没找到metavar的意思,这个是从别的文章扒下来的),在传入help参数后此行的提示就应该为:
# --urls=FILE Read URLs from the specified file
136 parser.add_option('', '--urls', dest='urls', metavar='FILE', help='Read URLs from the specified file')
# 设置parse的默认值
140 parser.set_defaults(verbose=False, display_errors=False)
# 解析args
142 (options, args) = parser.parse_args(sys.argv)
# 解析完args后,接下来就是对args中的各个参数的生效设定以及合法性校验
# 首先是verbose,如果传入参数带有--verbose的话,那么创建一个StreamHandler,设置其级别为DEBUG,这样运行程序的日志就都会出现在console上了,方便用于调试
143 if options.verbose:
144 console = logging.StreamHandler()
145 console.setLevel(logging.DEBUG)
146 formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
147 console.setFormatter(formatter)
148 log.addHandler(console)
149 log.info('turning on verbose logging mode')
# 接下来是display_errors,设置显示错误标志位
151 if options.display_errors:
152 log.info('turning display of errors ON')
153 display_errors = True
# 再下来是urls,判断传入的urls参数是否为文件,是:打印日志,否:程序退出
155 if options.urls:
156 if os.path.isfile(options.urls):
157 urls_txt = options.urls
158 log.info('using %s as urls.txt' % options.urls)
159 else:
160 log.error('%s is not a file' % options.urls)
161 print 'Error: %s is not a file' % options.urls
162 sys.exit(1)
# 最后是hooks,与urls一致
164 if options.hooks:
165 if os.path.isfile(options.hooks):
166 hooks_py = options.hooks
167 log.info('using %s as hooks.py' % options.hooks)
168 else:
169 log.error('%s is not a file' % options.hooks)
170 print 'Error: %s is not a file' % options.hooks
171 sys.exit(1)
# 这段程序显而易见,偷懒不说了
173 # Created all needed folders
174 for needed_dir in (urlwatch_dir, cache_dir, scripts_dir):
175 if not os.path.isdir(needed_dir):
176 os.makedirs(needed_dir)
# 以下这段也不说了,值得一说的是shutil,又学到个新模块,shutil.copy(srt, dst)等价于sh中的cp srt dst,而shutil.copy2(srt, dst)等价于cp -p srt dst,拷贝的不仅是文件,还包括文件的属性(ownership,mode,timestamps ==)
178 # Check for required files
179 if not os.path.isfile(urls_txt):
···
192 if os.path.exists(urls_txt_example) and not os.path.exists(urls_txt_fn):
193 shutil.copy(urls_txt_example, urls_txt_fn)
194 if not options.hooks and os.path.exists(hooks_py_example) and not os.pat h.exists(hooks_py_fn):
195 shutil.copy(hooks_py_example, hooks_py_fn)
# 再往下,hooks_py其实里面只需要定义一个过滤器函数filter,可以利用正则式从结果中筛选需要的信息
206 if os.path.exists(hooks_py):
207 log.info('using hooks.py from %s' % hooks_py)
# 通过imp.load_source,将hooks_py导入工程,使得接下来能够使用hooks_py中的方法
208 hooks = imp.load_source('hooks', hooks_py)
# 判断filter是否为hooks模块的属性
209 if hasattr(hooks, 'filter'):
210 log.info('found and enabled filter function from hooks.py')
211 filter = hooks.filter
212 else:
213 log.warning('hooks.py has no filter function - ignoring')
# lambda在此等价于def filter(x, y):return y,在这种情况下,filter就等于传入的y参数
214 filter = lambda x, y: y
215 else:
216 log.info('not using hooks.py (file not found)')
217 filter = lambda x, y: y
# 这段是处理文件名的,将缓存文件夹中的文件名转为sha1加密后的密文,为了防止混淆?
# 用到了hashlib,hashlib.new('sha1')也可以等价于hashlib.sha1(),试了下,两种功能一样,应该是由于python的版本不同造成的差异吧,之后的处理都一样,update,digest,只不过用了hexdigest,用十六进制表示加密密文
219 for url in (x for x in open(urls_txt).read().splitlines() if not (x.startswi th('#') or x.strip()=='')):
220 log.info('processing URL: %s' % url)
221 if have_hashlib:
222 sha_hash = hashlib.new('sha1')
223 sha_hash.update(url)
224 else:
225 sha_hash = sha.new(url)
226 filename = os.path.join(cache_dir, sha_hash.hexdigest())
# 终于出现try了,urlwatch真正干活的东东就只两个,urllib2.urlopen和difflib.unified_diff,urllib这个东西比较庞大,以后再研究。
# 程序调用了Request于urlopen去获取页面,然后通过difflib.unified_diff去比较当前获取页面的内容与缓存文件的内容是否不同,风格类似sh中的diff
227 try:
228 request = urllib2.Request(url, None, headers)
229 data = filter(url, urllib2.urlopen(request).read())
230 if os.path.exists(filename):
231 log.info('%s exists - creating unified diff' % filename)
232 old_data = open(filename).read()
233 diff = ''.join(difflib.unified_diff(old_data.splitlines(1), data .splitlines(1)))
234 if len(diff) > 0:
235 log.info('%s has changed - adding diff' % url)
236 details += foutput('changed', url, diff, summary)
237 else:
238 log.info('%s has not changed' % url)
239 else:
240 log.info('%s does not exist - url is considered "new"' % filenam e)
241 details += foutput('new', url, None, summary)
242 log.info('writing current content of %s to %s' % (url, filename))
243 open(filename, 'w').write(data)
244 except urllib2.HTTPError, error:
245 log.error('got HTTPError while loading url: %s' % error)
246 if display_errors:
247 details += foutput('error', url, error, summary)
248 except urllib2.URLError, error:
249 log.error('got URLError while loading url: %s' % error)
250 if display_errors:
251 details += foutput('error', url, error, summary)
# 接下来是连续两个except捕捉异常
244 except urllib2.HTTPError, error:
248 except urllib2.URLError, error:
# 最后判断条件并输出结果
257 if len(summary) > 1:
268 if len(details) > 1:
--OVER,urlwatch比较简单,尽管我初学但还是看懂了,继续学习