美文网首页
Scrapy扩展

Scrapy扩展

作者: 岸与海 | 来源:发表于2019-01-07 22:06 被阅读0次

Scrapy CrawlSpider了解

scrapy通用爬虫

CrawlSpider它是Spider的派生类,Spider类的设计原则是只爬取start_url列表中的网页,而CrawlSpider类定义了一些规则Rule来提供跟进链接的方便的机制,从爬取的网页结果中获取链接并继续爬取的工作.

源码:
class CrawlSpider(Spider):
    rules = ()
    def __init__(self, *a, **kw):
        super(CrawlSpider, self).__init__(*a, **kw)
        self._compile_rules()

    #首先调用parse()来处理start_urls中返回的response对象
    #parse()则将这些response对象传递给了_parse_response()函数处理,并设置回调函数为parse_start_url()
    #设置了跟进标志位True
    #parse将返回item和跟进了的Request对象    
    def parse(self, response):
        return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)

    #处理start_url中返回的response,需要重写
    def parse_start_url(self, response):
        return []

    def process_results(self, response, results):
        return results

    #从response中抽取符合任一用户定义'规则'的链接,并构造成Resquest对象返回
    def _requests_to_follow(self, response):
        if not isinstance(response, HtmlResponse):
            return
        seen = set()
        #抽取之内的所有链接,只要通过任意一个'规则',即表示合法
        for n, rule in enumerate(self._rules):
            links = [l for l in rule.link_extractor.extract_links(response) if l not in seen]
            #使用用户指定的process_links处理每个连接
            if links and rule.process_links:
                links = rule.process_links(links)
            #将链接加入seen集合,为每个链接生成Request对象,并设置回调函数为_repsonse_downloaded()
            for link in links:
                seen.add(link)
                #构造Request对象,并将Rule规则中定义的回调函数作为这个Request对象的回调函数
                r = Request(url=link.url, callback=self._response_downloaded)
                r.meta.update(rule=n, link_text=link.text)
                #对每个Request调用process_request()函数。该函数默认为indentify,即不做任何处理,直接返回该Request.
                yield rule.process_request(r)

    #处理通过rule提取出的连接,并返回item以及request
    def _response_downloaded(self, response):
        rule = self._rules[response.meta['rule']]
        return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)

    #解析response对象,会用callback解析处理他,并返回request或Item对象
    def _parse_response(self, response, callback, cb_kwargs, follow=True):
        #首先判断是否设置了回调函数。(该回调函数可能是rule中的解析函数,也可能是 parse_start_url函数)
        #如果设置了回调函数(parse_start_url()),那么首先用parse_start_url()处理response对象,
        #然后再交给process_results处理。返回cb_res的一个列表
        if callback:
            #如果是parse调用的,则会解析成Request对象
            #如果是rule callback,则会解析成Item
            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

        #如果需要跟进,那么使用定义的Rule规则提取并返回这些Request对象
        if follow and self._follow_links:
            #返回每个Request对象
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

    def _compile_rules(self):
        def get_method(method):
            if callable(method):
                return method
            elif isinstance(method, basestring):
                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)

    def set_crawler(self, crawler):
        super(CrawlSpider, self).set_crawler(crawler)
        self._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True)

通过下面的命令可以快速创建 CrawlSpider模板 的代码:

scrapy genspider -t crawl 爬虫文件 域名

rules

CrawlSpider使用rules属性来决定爬虫的爬取规则,并将匹配后的url请求提交给引擎,完成后续的爬取工作。

在rules中包含一个或多个Rule对象,每个Rule对爬取网站的动作定义了某种特定操作,比如提取当前相应内容里的特定链接,是否对提取的链接跟进爬取,对提交的请求设置回调函数等。

class scrapy.spiders.Rule(
        link_extractor,
        callback = None,
        cb_kwargs = None,
        follow = None,
        process_links = None,
        process_request = None
)

link_extractor:是一个Link Extractor对象,用于定义需要提取的链接。

callback: 从link_extractor中每获取到链接得到Responses时,会调用参数所指定的值作为回调函数,该回调函数接收一个response作为其一个参数。

follow:是一个布尔(boolean)值,指定了根据该规则从response提取的链接是否需要跟进。如果callback为None,follow 默认设置为True ,否则默认为False。

process_links:指定spider中哪个的函数将会被调用,从link_extractor中获取到链接列表时将会调用该函数。该方法主要用来过滤。

process_request:指定处理函数,根据该Rule提取到的每个Request时,该函数将会被调用,可以对Request进行处理,该函数必须返回Request或者None


class scrapy.linkextractors.LinkExtractor(
    allow = (),
    deny = (),
    allow_domains = (),
    deny_domains = (),
    deny_extensions = None,
    restrict_xpaths = (),
    tags = ('a','area'),
    attrs = ('href'),
    canonicalize = True,
    unique = True,
    process_value = None
)

allow:满足括号中“正则表达式”的URL会被提取,如果为空,则全部匹配。

deny:满足括号中“正则表达式”的URL一定不提取(优先级高于allow)。

allow_domains:会提取的链接的domains。

deny_domains:一定不会被提取链接的domains。

restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。

下载中间件

下载中间件:处于引擎与下载器之间

反爬措施

  1. 基于请求头的反爬(合理构建请求头)
  2. 基于cookie的反爬(cookie池,文件存储,数据库存储)(如何获取cookies,如何验证cookie,怎么进行模拟登陆)
  3. 基于ip的反爬(代理,代理的原理,代理怎么获取?代理怎么检测?代理池?)
  4. 基于动态加载的网页?(ajax,js,jq)(selenium?无头.有头浏览器)
  5. 关于数据加密?(js,aPP,web网页,)
@classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        # 所有的request请求在交给下载器之前都会交给进入方法
        # Called for each request that goes through the downloader middleware.

        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        return None

    def process_response(self, request, response, spider):
        # 响应结果都会经过这个方法
        # Called with the response returned from the downloader.

        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response

    def process_exception(self, request, exception, spider):
        # 处理错误
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

scrapy.settings.py文件中的配置:

# 项目名称
BOT_NAME = 'downloadmiddler'

# 爬虫存储的文件路径
SPIDER_MODULES = ['downloadmiddler.spiders']

# 创建爬虫文件的模板,创建好的文件存放在这个目录下
NEWSPIDER_MODULE = 'downloadmiddler.spiders'

# 模拟浏览器请求
USER_AGENT = 'downloadmiddler (+http://www.yourdomain.com)'

# 设置是否遵守robots协议,默认TRUE遵守
ROBOTSTXT_OBEY = False

# 设置请求最大的并发数量(下载器处理的最大数量),默认16个
CONCURRENT_REQUESTS = 32

# 设置请求下载延时,默认为0.
DOWNLOAD_DELAY = 3

# 设置网站的最大并发请求数量,默认8个
CONCURRENT_REQUESTS_PER_DOMAIN = 16

# 设置某个IP下的最大并发请求数量,默认0个,如果非0,要注意网站并发就无效,请求的并发数量将只针对于IP,如果非零,下载延时则针对IP,而不是网站
CONCURRENT_REQUESTS_PER_IP = 16

# 是否携带cookie,默认为TRUE
COOKIES_ENABLED = False

# 是一个终端的扩展插件
TELNETCONSOLE_ENABLED = False

# 设置默认的请求头(cookie不要放在这里)
DEFAULT_REQUEST_HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
    }

# 设置和激活爬虫中间键
SPIDER_MIDDLEWARES = {
       'downloadmiddler.middlewares.DownloadmiddlerSpiderMiddleware': 543,
    }

# 设置和激活下载中间键
DOWNLOADER_MIDDLEWARES = {
        'downloadmiddler.middlewares.SeleniumDownloadMiddlerware': 543
    }

# 设置和激活管道文件,数字表示优先级,越小越高
ITEM_PIPELINES = {
       'downloadmiddler.pipelines.DownloadmiddlerPipeline': 300,
    }

# 设置扩展
EXTENSIONS = {
       'scrapy.extensions.telnet.TelnetConsole': None,
    }

# 自动限速的扩展,上一个请求和下一个请求之间的时间是不固定的,默认情况下,自动限速扩是没有打开的False
    AUTOTHROTTLE_ENABLED = True

# 初始的下载延时,默认为5秒
    AUTOTHROTTLE_START_DELAY = 5

# 最大下载延时
    AUTOTHROTTLE_MAX_DELAY = 60

# 针对于网站的最大的并行请求数量
    AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0

# debug调试模式,默认为False
    AUTOTHROTTLE_DEBUG = False

# 设置数据缓存,默认不开启
    HTTPCACHE_ENABLED = True

# 设置缓存的超时时间,为0代表永久有效
    HTTPCACHE_EXPIRATION_SECS = 0

# 设置缓存数据的存储路径
    HTTPCACHE_DIR = 'httpcache'

# 忽略某些状态码的请求结果
    HTTPCACHE_IGNORE_HTTP_CODES = []

# 开启缓存的一个扩展插件
    HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

# cookie debug模式,默认为Fales
    COOKIES_DEBUG = True

# 关于日志信息设置

Scrapy提供5层logging级别:

CRITICAL - 严重错误(critical)
ERROR    - 一般错误(regular errors)
WARNING  - 警告信息(warning messages)
INFO     - 一般信息(informational messages)
DEBUG    - 调试信息(debugging messages)

LOG_ENABLED   默认: True,启用logging
LOG_ENCODING  默认: 'utf-8',logging使用的编码
LOG_FILE      默认: None,在当前目录里创建logging输出文件的文件名
LOG_LEVEL     默认: 'DEBUG',log的最低级别
LOG_STDOUT    默认: False 如果为 True,进程所有的标准输出(及错误)将会被重定向到log中。例如,执行 print "hello" ,其将会在Scrapy log中显示


scrapy-redis

pip3 install scrapy-redis

修改设置文件
  1. 设置去重组件,使用的是scrapy_redis的去重组件,而不再使用scrapy框架自己的去重组件
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

  2. 设置调度器,使用的是scrapy_redis重写的调度器,而不再使用scrapy框架自己的调度器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"

  3. 可以实现断点爬取(请求的记录不会丢失,会存储在redis数据库中,不会清除redis的任务队列)
    SCHEDULER_PERSIST = True

  4. 设置任务队列的模式(三选一)
    SpiderPriorityQueue是scrapy_redis默认使用的队列模式(有自己的优点)
    SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"

使用了队列的形式,任务先进先出
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"

采用了核的形式,任务先进后出
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"

  1. 实现这个管道,可以将爬虫端获取的item数据,统一保存在redis数据库中
    'scrapy_redis.pipelines.RedisPipeline': 400,
  1. 数据库的相关信息
    指定要存储的redis数据库的主机ip
    REDIS_HOST = '127.0.0.1'

指定redis数据库主机的端口
REDIS_PORT = 6379

"xcfCrawlSpider:requests":存储的是请求的request对象
"xcfCrawlSpider:items":存储的爬虫端获取的items数据
"xcfCrawlSpider:dupefilter":存储的指纹(为了实现去重)
127.0.0.1:6379> type xcfCrawlSpider:requests
zset
127.0.0.1:6379> type xcfCrawlSpider:items
list
127.0.0.1:6379> type xcfCrawlSpider:dupefilter
set

第一中情况:只设置settings.py文件,并没有实现分布式,知识使用了sctapy_redis的数据存储和去重功能

第二中情况:实现通用爬虫的分布式爬虫

    from scrapy_redis.spiders import RedisCrawlSpider

    #继承制:RedisCrawlSpider
    class MyCrawler(RedisCrawlSpider):
        """Spider that reads urls from redis queue (myspider:start_urls)."""
        name = 'mycrawler_redis'
        allowed_domains = ['dmoz.org']
        #缺少了start_url,多了redis_key:根据redis_key从redis
        #数据库中获取任务
        redis_key = 'mycrawler:start_urls'


    启动爬虫:scrapy crawl 爬虫名称

    现象:爬虫处于等待状态

    需要设置起始任务:
    lpush mycrawler:start_urls 目标url

第三中情况:实现scrpy.spider爬虫的分布式爬虫

  from scrapy_redis.spiders import RedisSpider

    #继承制:RedisSpider
    class MyCrawler(RedisSpider):
        """Spider that reads urls from redis queue (myspider:start_urls)."""
        name = 'mycrawler_redis'
        allowed_domains = ['dmoz.org']
        #缺少了start_url,多了redis_key:根据redis_key从redis
        #数据库中获取任务
        redis_key = 'mycrawler:start_urls'


    启动爬虫:scrapy crawl 爬虫名称

    现象:爬虫处于等待状态

    需要设置起始任务:
    lpush mycrawler:start_urls 目标url

相关文章

  • scrapy 爬虫

    scrapy 官方文档 scrapy的信号量文档使用 scrapy的扩展文档使用 scrapy统计数据收集 安装:...

  • Scrapy扩展

    先看一个例子 解释 Scrapy API的主要入口是 Crawler 的实例对象, 通过类方法 from_craw...

  • Scrapy扩展

    Scrapy CrawlSpider了解 scrapy通用爬虫 CrawlSpider它是Spider的派生类,S...

  • Scrapy流程及模块介绍

    参考资料:python网络爬虫开发实战 1.scrapy的优势 Scrapy框架具有高效爬取速率,相关扩展组件多,...

  • Scrapy爬虫入门教程 Settings(设置)

    设置 Scrapy设置允许您自定义所有Scrapy组件的行为,包括核心,扩展,管道和爬虫本身。 设置的基础结构提供...

  • scrapy信号signals

    Scrapy广泛使用信号来通知特定事件发生的时间。 可以在Scrapy项目中捕获一些这些信号(例如,使用扩展名)来...

  • Scrapy(二)- 自定义扩展,配置文件详解

    Scrapy 自定义扩展 自定义扩展时,利用信号在指定位置注册指定操作。 最后需要在settings.py里的修改...

  • (2018-05-22.Python从Zero到One)6、(爬

    scheduler.py 此扩展是对scrapy中自带的scheduler的替代(在settings的SCHEDU...

  • scrapy实战笔记

    一,基础 scrapy优势:异步IO,性能强;内置功能丰富(css,xpath);易扩展爬虫简要步骤:URL分析,...

  • Scrapy 扩展:解决scrapy-redis 调度空跑问题

    一:前言 正常情况下使用scrapy-redis 做分布式使用,这个比较方便简单,但是有个问题:当redis调度队...

网友评论

      本文标题:Scrapy扩展

      本文链接:https://www.haomeiwen.com/subject/geiprqtx.html