CrawlSpider的使用

CrawlSpider是爬取那些具有一定规则网站的常用的爬虫,它基于Spider并有一些独特属性

  • rules: 是Rule对象的集合,用于匹配目标网站并排除干扰
  • parse_start_url: 用于爬取起始响应,必须要返回ItemRequest中的一个。

rules是Rule对象的集合

  • rules的参数

link_extractor, : linkExtractor对象
callback=None, : 设置回调函数
follow=None, : 设置是否跟进
process_links=None, :可以设置回调函数,对所有提取到的url进行拦截
process_request=identity : 可以设置回调函数,对request对象进行拦截

其中的link_extractor既可以自己定义,也可以使用已有LinkExtractor类,主要参数为:

*   allow:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。
*   deny:与这个正则表达式(或正则表达式列表)不匹配的URL一定不提取。
*   allow_domains:会被提取的链接的domains。
*   deny_domains:一定不会被提取链接的domains。
*   **restrict_xpaths**:使用**xpath**表达式,和**allow**共同作用过滤链接。还有一个类似的restrict_css

以Chinaz为例:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from china.items import ChinazprojectWebInfoItem

class ChinazSpider(CrawlSpider):
    # 爬虫名称
    name = 'chinaz'
    # 允许爬去的域
    allowed_domains = ['chinaz.com']
    # 起始url地址
    start_urls = ['http://top.chinaz.com/hangyemap.html']
    # 存放定制的获取链接的规则对象(可以是一个列表也可以是元组)
    # 根据规则提取到的所有链接,会由crawlspider构建request对象,并交给引擎处理
    '''
        LinkExtractor : 设置提取链接的规则(正则表达式)
        allow=(), : 设置允许提取的url
        restrict_xpaths=(), :根据xpath语法,定位到某一标签下提取链接
        restrict_css=(), :根据css选择器,定位到某一标签下提取链接
        deny=(), : 设置不允许提取的url(优先级比allow高)
        allow_domains=(), : 设置允许提取url的域
        deny_domains=(), :设置不允许提取url的域(优先级比allow_domains高)
        unique=True, :如果出现多个相同的url只会保留一个
        strip=True :默认为True,表示自动去除url首尾的空格
    '''
    '''
    rule
        link_extractor, : linkExtractor对象
        callback=None,  : 设置回调函数  
        follow=None, : 设置是否跟进
        process_links=None, :可以设置回调函数,对所有提取到的url进行拦截
        process_request=identity : 可以设置回调函数,对request对象进行拦截
    '''
    rules = (
        # 规则对象'<a href="http://top.chinaz.com/hangye/index_yule_yinyue.html">音乐网站</a>'
        Rule(LinkExtractor(allow=r'http://top.chinaz.com/hangye/index_.*?html',
                           restrict_xpaths='//div[@class="Taright"]'),
             callback='parse_item',
             follow=True),
    )
    # 注意: CrawlSpider中一定不要出现parse回调方法
    def parse_item(self, response):
        print(response.status, response.url)
        '''
        解析分页的网站数据,提取后交给item处理
        '''
        webInfos = response.xpath('//ul[@class="listCentent"]/li')
        for webInfo in webInfos:
            web_item = ChinazprojectWebInfoItem()
            # 封面图片
            web_item['coverImage'] = webInfo.xpath('.//div[@class="leftImg"]/a/img/@src').extract_first('')
            # 标题
            web_item['title'] = webInfo.xpath('.//h3[@class="rightTxtHead"]/a/text()').extract_first('')
            # 域名
            web_item['domenis'] = webInfo.xpath('.//h3[@class="rightTxtHead"]/span[@class="col-gray"]/text()').extract_first('')
            # 周排名
            web_item['weekRank'] = webInfo.xpath('.//div[@class="RtCPart clearfix"]/p[1]/a/text()').extract_first('')
            # 反连接数
            web_item['ulink'] = webInfo.xpath('.//div[@class="RtCPart clearfix"]/p[4]/a/text()').extract_first('')
            # 网站简介
            web_item['info'] = webInfo.xpath('.//p[@class="RtCInfo"]/text()').extract_first('')
            # 得分
            web_item['score'] = webInfo.xpath('.//div[@class="RtCRateCent"]/span/text()').re('\d+')[0]
            # 排名
            web_item['rank'] = webInfo.xpath('.//div[@class="RtCRateCent"]/strong/text()').extract_first('')
            print(web_item)
            yield web_item

CrawlSpider如何工作的?

因为CrawlSpider继承了Spider,所以具有Spider的所有函数。
首先由start_requestsstart_urls中的每一个url发起请求(make_requests_from_url),这个请求会被parse接收。在Spider里面的parse需要我们定义,但CrawlSpider定义parse去解析响应(self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)
_parse_response根据有无callback,followself.follow_links执行不同的操作

eg:

    def _parse_response(self, response, callback, cb_kwargs, follow=True):
    ##如果传入了callback,使用这个callback解析页面并获取解析得到的reques或item
        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
    ## 其次判断有无follow,用_requests_to_follow解析响应是否有符合要求的link。
        if follow and self._follow_links:
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

其中_requests_to_follow又会获取link_extractor(这个是我们传入的LinkExtractor)解析页面得到的link(link_extractor.extract_links(response)),对url进行加工(process_links,需要自定义),对符合的link发起Request。使用.process_request(需要自定义)处理响应。

CrawlSpider如何获取rules?

CrawlSpider类会在__init__方法中调用_compile_rules方法,然后在其中浅拷贝rules中的各个Rule获取要用于回调(callback),要进行处理的链接(process_links)和要进行的处理请求(process_request)

eg:

    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)

Rule是怎么样定义的

    class Rule(object):

        def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):
            self.link_extractor = link_extractor
            self.callback = callback
            self.cb_kwargs = cb_kwargs or {}
            self.process_links = process_links
            self.process_request = process_request
            if follow is None:
                self.follow = False if callback else True
            else:
                self.follow = follow

因此LinkExtractor会传给link_extractor。

有callback的是由指定的函数处理,如果没有callback的由哪个函数处理?

`_parse_response`会处理有`callback`的(响应)respons。
cb_res = callback(response, **cb_kwargs) or ()
而`_requests_to_follow`会将`self._response_downloaded`传给`callback`用于对页面中匹配的url发起请求(request)。
r = Request(url=link.url, callback=self._response_downloaded)

如何在CrawlSpider进行模拟登陆

CrawlSpider和Spider一样,都要使用start_requests发起请求

以知乎为例:

##替换原来的start_requests,callback为
def start_requests(self):
    return [Request("http://www.zhihu.com/#signin", meta = {'cookiejar' : 1}, callback = self.post_login)]
def post_login(self, response):
    print 'Preparing login'
    #下面这句话用于抓取请求网页后返回网页中的_xsrf字段的文字, 用于成功提交表单
    xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]
    print xsrf
    #FormRequeset.from_response是Scrapy提供的一个函数, 用于post表单
    #登陆成功后, 会调用after_login回调函数
    return [FormRequest.from_response(response,   #"http://www.zhihu.com/login",
                        meta = {'cookiejar' : response.meta['cookiejar']},
                        headers = self.headers,
                        formdata = {
                        '_xsrf': xsrf,
                        'email': 'z1996914@outlook.com',
                        'password': '********'
                        },
                        callback = self.after_login,
                        dont_filter = True
                        )]
#make_requests_from_url会调用parse,就可以与CrawlSpider的parse进行衔接了
def after_login(self, response) :
    for url in self.start_urls :
        yield self.make_requests_from_url(url)

仅为个人学习小结,若有错处,欢迎指正~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容