zoukankan      html  css  js  c++  java
  • CrawlSpider源码分析

    CrawlSpider是对Spider做了进一步的封装, 使得该类可以直接爬取一个网站.也就是说CrawlSpider是为了爬取整个网站设计的

    CrawlSpider和Spider一样, 入口都是start_request, 如果想要模拟登陆, 可以重载这个函数, 然后callback自己定义的登陆函数, 

    关于模拟登陆可以参考之前写的 模拟登陆知乎 

    CrawlSpider不同于Spider的是,:

    1. 不能重载parse函数, 因为CrawlSpider对parse函数做了重载, 实现了相关的逻辑, 所以不能重载,

    相应的可以重载 parse_start_url这个函数.

    2. 多出来了一个rules , rules中指明了你要对这个网站的那些网页进行爬取, 那些网页不用进行爬取, 通过正则表达式匹配成功的才会做进一步的处理

    有关rules下面会做进一步的说明, rules是如何起作用的

    下面来解析CrawlSpider的源码

    首先是parse函数:

        def parse(self, response):
            return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)

    从代码中也能看到, 其中调用了CrawlSpider自己定义的函数 _parse_response, 这也是不能被重载的原因

    下面是_parse_response函数:

        def _parse_response(self, response, callback, cb_kwargs, follow=True):
            if callback:
                cb_res = callback(response, **cb_kwargs) or ()
                cb_res = self.process_results(response, cb_res)
                for requests_or_item in iterate_spider_output(cb_res):
                    yield requests_or_item
    
            if follow and self._follow_links:
                for request_or_item in self._requests_to_follow(response):
                    yield request_or_item

    其中的参数callback就是 parse_start_url, 就和Spider中的parse函数功能一样, 

    如果没有写parse_start_url和process_result, 那么第一个if就没什么用, 当然我们也可以自己重载写上自己的定义, parse_start_url

    返回的结果交给process_result进行处理, process_result返回的结果进行迭代, 然后yield出去

    第二个if之最重要的一点:

    当follow和self._follow_links其中有一个为False时, 都不会使rules生效.也就是说if后面的代码说明了rules是怎么生效的

    现在跟踪_requests_to_follow函数:

         def _requests_to_follow(self, response):
            if not isinstance(response, HtmlResponse):
                return
            seen = set()
            for n, rule in enumerate(self._rules):
                links = [lnk for lnk in rule.link_extractor.extract_links(response)
                         if lnk not in seen]
                if links and rule.process_links:
                    links = rule.process_links(links)
                for link in links:
                    seen.add(link)
                    r = self._build_request(n, link)
                    yield rule.process_request(r)

    首先判断response是否是网页的访问, 不是的话, 就直接结束

    seen集合是为了去除该网页中相同的网页

    for语句是将self._rules变为可迭代对象,

    现在跟踪self._rules, 而该成员变量在_compile_rules中定义, 而compile_rules是在CrawlSpider初始化的时候被调用

    compile_rules:

    def _compile_rules(self):
        def get_method(method):
            if callable(method):
                return method
            elif isinstance(method, six.string_types):
                return getattr(self, method, None)
    
        self._rules = [copy.copy(r) for r in self.rules]
        for rule in self._rules:
            rule.callback = get_method(rule.callback)
            rule.process_links = get_method(rule.process_links)
            rule.process_request = get_method(rule.process_request)

    首先是对rules进行浅拷贝,然后对rules中的每个rule进行处理, 其中callback就是rule中自己指明的要调用的函数, 另外两个函数不做分析

    现在回到_requests_to_follow

    for语句之后的代码就是根据rule中的规则提取出网页中的所有链接, 然后将所得链接生成request, 之后调用_parse_response函数, 

    进行进一步的爬取, 直到将网站中的所有网页爬取完毕

    当爬取的网站需要user_agent时, 可以修改_build_request函数, 直接添加headers即可

  • 相关阅读:
    蓝牙搜索
    Log4cpp介绍及使用
    单独卸载vs2010帮助文档HelpView之后的独立安装教程
    C++Builder RAD Studio XE, UTF-8 String 转换为 char * 字符串的最简单方式, 常用于sqlite3开发
    vs2012 MSDN帮助文档离线包下载安装方法
    关于OBJ/LIB格式,我以前有个总结
    关于C++ const 的全面总结
    在 C++Builder 工程里调用 DLL 函数
    c++builder调用VC的dll以及VC调用c++builder的dll
    C++Builder及VC的库相互调用
  • 原文地址:https://www.cnblogs.com/fenglj/p/7910089.html
Copyright © 2011-2022 走看看