博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CrawlSpider源码分析
阅读量:4610 次
发布时间:2019-06-09

本文共 2904 字,大约阅读时间需要 9 分钟。

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即可

转载于:https://www.cnblogs.com/fenglj/p/7910089.html

你可能感兴趣的文章
android 中检查设备是否有网络可用
查看>>
linux磁盘命令-lsblk显现磁盘阵列分组
查看>>
vuex在页面中以对象展开运算符形式引入报错解决
查看>>
NET Remoting 示例
查看>>
文件系统典型实现方式
查看>>
20155207王雪纯 2006-2007-2 《Java程序设计》第1 周学习总结
查看>>
搭建jenkins集群node结点
查看>>
一个可收缩的panel
查看>>
ASP.NET IIS 支持PUT、DELETE请求
查看>>
网站建设中帝国cms如何循环调用栏目下级分类
查看>>
php对象的传递——“通过引用传递”or“传递的是object identifier”?
查看>>
windows(msvc)下编译boost库
查看>>
统计文件夹的大小
查看>>
websocket实现群聊和单聊(转)
查看>>
面试简单整理之zookeeper
查看>>
把你的英语用起来-七天行动-置之死的而后生
查看>>
react 原理集合
查看>>
The primitive Java types
查看>>
个人在AS的一些安卓适配经验
查看>>
pat1009
查看>>