返回介绍

3.1 为链接爬虫添加缓存支持

发布于 2024-02-05 23:37:18 字数 3165 浏览 0 评论 0 收藏 0

要想支持缓存,我们需要修改第1章中编写的download 函数,使其在URL下载之前进行缓存检查。另外,我们还需要把限速功能移至函数内部,只有在真正发生下载时才会触发限速,而在加载缓存时不会触发。为了避免每次下载都要传入多个参数,我们借此机会将download 函数重构为一个类,这样参数只需在构造方法中设置一次,就能在后续下载时多次复用。下面是支持了缓存功能的代码实现。

class Downloader:
    def __init__(self, delay=5,
        user_agent='wswp', proxies=None,
            num_retries=1, cache=None):
        self.throttle = Throttle(delay)
        self.user_agent = user_agent
        self.proxies = proxies
        self.num_retries = num_retries
        self.cache = cache

    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.num_retries > 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.user_agent}
           result = self.download(url, headers, proxy,
              self.num_retries)
           if self.cache:
              # save result to cache
              self.cache[url] = result
        return result['html']

    def download(self, url, headers, proxy, num_retries,
        data=None):
        ...
    return {'html': html, 'code': code}

下载类的完整源码可以从`https://bitbucket.org/` `wswp/code/src/tip/chapter03/downloader.py`获取。

前面代码中的Download 类有一个比较有意思的部分,那就是__call__ 特殊方法,在该方法中我们实现了下载前检查缓存的功能。该方法首先会检查缓存是否已经定义。如果已经定义,则检查之前是否已经缓存了该URL。如果该URL已被缓存,则检查之前的下载中是否遇到了服务端错误。最后,如果也没有发生过服务端错误,则表明该缓存结果可用。如果上述检查中的任何一项失败,都需要正常下载该URL,然后将得到的结果添加到缓存中。这里的download 方法和之前的download 函数基本一样,只是在返回下载的HTML时额外返回了HTTP状态码,以便在缓存中存储错误码。当然,如果你只需要一个简单的下载功能,而不需要限速或缓存的话,可以直接调用该方法,这样就不会通过__call__ 方法调用了。

而对于cache 类,我们可以通过调用result = cache[url] 从cache 中加载数据,并通过cache[url] = result 向cache中保存结果。大家应该很熟悉这种便捷的接口写法,因为这也是Python内建字典数据类型的使用方式。为了支持该接口,我们的cache 类需要定义__getitem__() 和__setitem__() 这两个特殊的类方法。

此外,为了支持缓存功能,链接爬虫的代码也需要进行一些微调,包括添加cache 参数、移除限速以及将download 函数替换为新的类等,如下面的代码所示。

def link_crawler(..., cache=None):
    crawl_queue = [seed_url]
    seen = {seed_url: 0}
    num_urls = 0
    rp = get_robots(seed_url)
    D = Downloader(delay=delay, user_agent=user_agent,
        proxies=proxies, num_retries=num_retries, cache=cache)

    while crawl_queue:
        url = crawl_queue.pop()
        depth = seen[url]
        # check url passes robots.txt restrictions
        if rp.can_fetch(user_agent, url):
            html = D(url)
            links = []
            ...

到目前为止,这个网络爬虫的基本架构已经准备好了,下面就要开始构建实际的缓存了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文