WSWP(用 python写爬虫) 笔记三:为爬虫添加缓存网页内容功能
来源:互联网 发布:奇游加速器mac 编辑:程序博客网 时间:2024/06/01 07:19
前面已经实现了一个具有数据爬取的爬虫。如果新增需求还要再抓取另一个字段,比如前面的爬虫中要求增加一个国旗图片的url,又该怎么做呢?想要抓取新增的字段,需要重新下载整个需要爬取的网站。对于小型网站来说,可能不算特别大的问题,但是对于那些百万级数据的网站而言,重新下载可能需要耗费很长一段时间。因此,对已爬取的网页进行缓存的方案可以让每个网页只下载一次。
为链接爬虫添加缓存支持
修改上一个爬虫中的downloader.py中的download函数,使其在开始下载网页之前先进性缓存检查,还需要把限速的功能移植到函数内部,这样只有在发生真正下载的时候才会触发限速,而通过加载缓存则不会触发。为了避免每次下载都需要传入多个参数,将download函数重构为一个类,这样参数只需要在构造方法中设置一次,就能在后续下载中多次复用。代码如下:
# downloader.pyimport urllib.requestimport urllib.parseimport urllib.errorfrom .Throttle import Throttleimport socketimport randomDEFAULT_AGENT = 'wswp'DEFAULT_DELAY = 5DEFAULT_RETRIES = 1DEFAULT_TIMEOUT = 60class Downloader: def __init__(self,delay=DEFAULT_DELAY,userAgent=DEFAULT_AGENT,proxies=None,numRetries=DEFAULT_RETRIES, timeOut=DEFAULT_TIMEOUT, opener=None,cache=None): socket.setdefaulttimeout(timeOut) self.throttle = Throttle(delay) self.userAgent = userAgent self.proxies = proxies self.numRetries = numRetries self.opener = None def __call__(self, url): result = None if self.cache: try: result = self.cache[url] except KeyError: # url is not available in cache pass else: if self.numRetries >0 and 500<=result['code']<600: # server error so ignore result from cache and re-download result = None if result is None: # result was not loaded from cache so still need to download self.throttle.wait(url) proxy = random.choice(self.proxies) if self.proxies else None headers = {'User-agent': self.userAgent} result = self.download(url, headers, proxy=proxy,numRetries=self.numRetries) if self.cache: # save result to cache self.cache[url] = result return result['html'] def download(self, url, headers, proxy, numRetries, data=None): print("正在下载:", url) request = urllib.request.Request(url, data, headers) opener = self.opener or urllib.request.build_opener() if proxy: proxyParams = {urllib.parse.urlparse(url).scheme: proxy} opener.add_handler(urllib.request.ProxyHandler(proxyParams)) try: response = opener.open(request) html = response.read() code = response.code except urllib.error.URLError as e: print('下载错误:', e.reason) html = '' if hasattr(e, 'code'): code = e.code if numRetries > 0 and 500 <= code < 600: return self.download(url, headers, proxy, numRetries - 1, data) else: code = None return {'html':html,'code':code}
上面的代码中Downloader类中有一个比较有意思的部分,那就是__call__特殊方法,在该方法中实现了下载前检查缓存的功能。首先会检查缓存是否已经定义,如果已经定义,则检查之前是否已经缓存了该url,如果已经缓存,则检查之前的下载中是否遇到了服务器端错误。如果检测到上述检查中的任何一项失败,都需要重新下载该网页,然后将缓存结构添加到缓存中。这里的download方法参数和之间的download函数基本一致,只是在返回下载的html的时候多加了一个状态码,该方法也可以直接调用。proxies是一个代理列表,通过随机获取的方式来绕过一定的反爬虫机制。
对于cache类,可以通过调用result=cache[url]从cache中加载数据,并通过cache[url] = resutl向cache中保存结果。这种便捷的接口写法也是Python中字典数据类型的使用方式。为了支持该接口,cache类需要定义__getitem__()和__setitem__()这两个特殊的类方法。
除此之外,为了支持缓存功能,链接爬取模块的代码也要进行一些微调,包括添加cache参数、移除限速以及将download函数替换为新的类等。代码如下所示:
# downloader.pydef linkCrawler(seedUrl, linkRegex=None, delay=5, maxDepth=-1, maxUrls=-1, headers=None, userAgent='wswp', proxies=None, numRetries=1, scrapeCallBack=None,cache=None): """ Crawl from the given seed URL following links matched by linkRegex :param seedUrl: 起始url :param linkRegx: 链接匹配的正则表达式 :param delay: 延迟时间 :param maxDepth: 最深的层次 :param maxUrls: 最多的url数量 :param headers: http请求头 :param userAgent: http头中的userAgent选项 :param proxy: 代理地址 :param numRetries: 重新下载次数 :return: """ crawlQueue = deque([seedUrl]) seen = { seedUrl:0} numUrls = 0 rp = getRobots(seedUrl) Down = Downloader(delay=delay,userAgent=userAgent,proxies=proxies,numRetries=numRetries,cache=cache) while crawlQueue: url = crawlQueue.pop() if rp.can_fetch(userAgent, url): html = Down(url) links = [] if scrapeCallBack: links.extend(scrapeCallBack(url, html) or []) depth = seen[url] if depth != maxDepth: if linkRegex: links.extend(link for link in getLinks(html) if re.match(linkRegex, link)) for link in links: link = normalize(seedUrl, link) if link not in seen: seen[link] = depth + 1 if sameDomain(seedUrl, link): crawlQueue.append(link) numUrls += 1 if numUrls == maxUrls: break else: print('Blocked by robots.txt',url)
到目前为止,这个网络爬虫的基本架构已经搭建好了,接下来就要开始构建实际的缓存了。
- WSWP(用 python写爬虫) 笔记三:为爬虫添加缓存网页内容功能
- WSWP(用 python写爬虫) 笔记四:实现缓存功能
- WSWP(用 python写爬虫) 笔记五:并发爬虫
- WSWP(用python写网络爬虫)笔记 一:实现简单爬虫
- WSWP(用python写爬虫)笔记二:实现链接获取和数据存储爬虫
- Python 爬虫笔记(三)
- python爬虫笔记(三)
- 用python写的多线程网页爬虫
- python 用爬虫写网页测试
- 用python写网络爬虫-下载网页
- 学习python写网络爬虫(三)
- 【Python爬虫】添加高级功能
- 用Python写网络爬虫系列(三)表单处理
- 网页爬虫(Python)
- 用python 写网络爬虫 学习笔记
- 《用python写网络爬虫》笔记1
- 《用python写网络爬虫》笔记2
- 用python写网络爬虫笔记
- 服务注册与发现以及Zookeeper的引入
- Java知识---awt--布局
- 29-类中的函数重载
- [spark] Task成功执行的结果处理
- 21. yii 2 library
- WSWP(用 python写爬虫) 笔记三:为爬虫添加缓存网页内容功能
- Java JFrame隐藏标题栏以及最大化最小化关闭和拖动
- Android Studio 结合Git的使用(一)
- Centos7 开启BBR加速
- 文章标题
- 算法(4)购物篮分析
- 单列模式实例
- linux作业练习(10.21/22)
- GCD 之dispatch source