定制信息是保存在modname这个字典变量中,键字就是对应的网站域名,值则是一个三元的tuple。第一项是对应的解析模块名(注意没有.py后缀)。第二项是网站中文名。第三项是网站的URL地址。
只要向get_mod(domain)函数传入URL的域名信息就可以得到对应的处理模块。如果要添加新的网站的支持,在编写好相应的定制模块后,将其配置在modname中即可。
4. 如何编写定制模块
编写定制模块主要的工作就是实现前面所讲的三个函数。读者可以参考工具中已经支持的网站的定制模块代码。
这里采用了正则表达式进行相应的文本的分析和提取处理。以分析新浪读书频道目录页面为例,看一下如何编写parse_index。
它的目录链接文本格式为:
<li><a href=/nzt/live/fin/xinjiminbd/1.shtml target=_blank class=a03>了解证券投资基金</a>
通过比较分析可以得知所有带有target=_blank class=a03字符串的a标签都是章节的链接,因此只要把它们分析出来即可。于是正则式定义为:
r_index = re.compile(r'<a href=([^\s]+) target=_blank class=a03>(.*?)</a>', re.DOTALL)
则parse_index函数的实现即为:
def parse_index(text, proxy=None):
s = []
for (url, title) in r_index.findall(text):
title = title.replace(' ', ' ')
yield url, tools.to_utf8(title)
其他的处理类似。因为每个网站可能都有不同,因此要仔细分析,但是原理差异不大。
5. 多线程下载
采用多线程可以充分利用网络带宽,提高下载的效率。
线程类定义如下:
import threading
class Parse(threading.Thread):
def __init__(self, book_name, q, lock, proxy=None):
threading.Thread.__init__(self)
self.q = q
self.lock = lock
self.proxy = proxy
self.book_name = book_name
self.setDaemon(True)
def run(self):
while not self.q.empty():
(id, url, title) = self.q.get()
parse_page(self.book_name, id, url, title, self.lock, self.proxy)
可以看出,线程类在创建时会传入一个q参数。它是一个外部队列,用于存放所有要下载的URL地址。使用Python自带的Queue的好处是:当多线程在从队列中取数据时,它使线程安全的。在线程的run方法中为具体的处理过程:它会不停从队列中取出要下载的地址,然后抓取页面,再进行正文地分析处理,直到队列为空,则结束处理并退出。
|