scrapy爬虫框架概览【基础使用】

Scrapy框架

架构

  1. Engine - 引擎:处理数据流、触发事务。
  2. item - 项目:数据结构,类。
  3. Schedul - 调度器:处理请求队列。
  4. Download - 下载器:请求。
  5. Spiders - 蜘蛛:爬取逻辑和网页解析规则。
  6. item Pipeline - 项目管道:处理结果数据,清洗入库等。
  7. Downloader Midddlewares - 下载器中间件
  8. Spider Midddlewares - 蜘蛛中间件

数据流

命令行调用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IIYMnys6-1638326526821)(https://note.youdao.com/yws/res/303/WEBRESOURCEf07c5e7dcbd7ba271b5b7e2023d740e8)]

  1. 子项目
  2. Engine找到对应的Spider,并获取第一个url。
  3. spider将第一个url发送给调度器。
  4. 调度器返回队列中的url给engine,engine将url通过中间件发送给Downloader下载器请求页面。
  5. 下载器请求完毕,将响应结果发给engine,engine转发给spider。
  6. spider处理response,提取到item或新的请求。返回给engine。
  7. engine把item发送给pipline,url发送给调度器。

项目结构

scrapy startproject tutorial

在这里插入图片描述

scrapy genspider qutes qutes.toscrape.com

在这里插入图片描述

项目

item

在这里插入图片描述

用于保存数据对象,用法与字典类似(item[‘title’]=‘标题’)。定义需要的字段。

spider

在这里插入图片描述

  1. name:Spider子项目的名字。(启动子项目,scrapy crawl name ,唯一)
  2. allowed_domains:允许这个子项目爬取的域名。
  3. start_urls:Spider最开始的启动url列表。
  4. parse():start_urls里面的url被请求之后,返回的响应体就会传到这个方法做处理,然后返回item或者新的请求。
def parse(self, response):
    article_list = response.css(".common-list")
    article_list = article_list.xpath(".//ul/li")
    for article in article_list:
        item = ArticleItem()
        item['link'] = article.xpath(".//a/@href").extract_first()
        item['title'] = article.xpath(".//a/@title").extract_first()
        item['content'] = article.xpath(".//a/text()").re_first('(.*)')
        # yield item # 返回item对象 交给piplines处理
        # yield scrapy.Request(url=item['link'],meta={'item':item},callback=self.parse_detail) 
        # 返回一个新的请求,请求之后的响应体交给自己定义的parse_detail方法处理,若有参数需要传递,用meta传递和提取。
pipline

数据提取完成,item构造完毕之后,可以在启动子项目时以添加命令行参数的方式保存到文件中,如:

  • scrapy crawl quotes -o quotes.json # 保存为JSON文件
  • scrapy crawl quotes -o quotes.csv # 保存为csv|xml|pickle|marshal文件
  • scrapy crawl quotes -o ftp://user:pass@ftp.example.com/path/to/quote/quotes/csv # 也可以保存到远程

除此之外,如果有更复杂的需求,可以在pipline中编写:

  1. pipline用法

    1. pipline表达为一个Pipline类,在这个类中定义一个process_item()方法,启用这个类后,就会调用这个方法。这个方法必须返回一个item对象或者一个DropItem异常(需要导入 from scrapy.exceptions import DropItem)。
    2. 在下例中,定义了两个pipline类:
      • 第一个类ArticlePipeline希望实现对item对象中数据的清洗。如,截取标题的前50个字。
      • 第二个类MongoPipeline则希望将item对象存入mongodb数据库中。在from_crawler类方法中通过全局配置参数cralwer获取到settings.py中的全局配置。open_spider、close_spider会分别在Spider开启或关闭时调用。
        在这里插入图片描述
  2. pipeline调用方式

    1. spider返回item之后按优先级顺序调用所有的Pipeline类方法。
    2. Pipeline类定义好之后,如需调用需要在settings.py中,将类添加到ITEM_PIPELINES。
      在这里插入图片描述

用法

spider的用法

定义爬取网站的动作;分析爬取下来的网页。
  1. name:爬虫名称,是定义Spider名字的字符串。Spider的名字定义了Scrapy如何定位并初始化Spider,它必须是唯一的。常用的命名方式是以域名的名称来命名。
  2. allowed_domains:允许爬取的域名,是可选配置,不在此范围的连接不会被跟进爬取。
  3. start_urls:起始url。相当于调度器初始值。
  4. custom_settings:spider配置,覆盖全局设置。类变量
  5. crawler:由from_crawler()设置,用于读取配置信息。
  6. settings:它是一个Setting对象,用于获取全局变量。
  7. start_requests():初始请求。必须返回一个可迭代对象。
  8. parse():当Response响应体没有回调函数时,就会调用这个函数。
  9. closed():Spider关闭时调用。用于释放资源等。

下载中间件Dowload Middleware的用法

调度器将请求发送给下载器以及下载器将响应发送给Spider时会经过下载中间件

说明
下载中间件可以用于修改User-Agent、处理重定向、设置代理、失败重试、设置Cookies等功能。
  1. 每个中间件包含一个或多个方法,其中核心方法有三个,
  • process_request(request,spider) # 在请求被engine发送给下载器前调用 #return requests\response\None\exception
  • process_response(request,response,spider) # 下载器执行请求之后将响应体发送给sppider之前 #return response\None\exception
  • process_exception(request,exception,spider) # 当下载器或process_request抛出异常时调用 #return requests\response\None
  1. scrapy 提供失败重试、自动重定向等等中间件,其中每个中间件按优先级先后执行。对于process_request()方法来说,优先级数字越小越显被调用,对于process_response()方法来说优先级越大越先调用
返回值
  1. process_request返回值为None、Response对象、Request对象之一,或者抛出IgnoreRequest异常
  • 返回为None,按优先级后续的中间件接着执行process_request方法(可以理解为修改request方法
  • 返回为Response对象,执行低优先级的process_response方法(相当于对响应体信息处理
  • 返回为Request对象,低优先级中间件停止执行,然后将这个Request添加到调度器。(相当于重构了一个新的请求
  • 抛出IgnoreRequest异常,低优先级的process_exception就会依次执行,若最终还是异常就回调这个请求的errorback(),若还是没有处理,则被忽略
  1. process_response返回值为Response对象、Request对象之一,或者抛出IgnoreRequest异常。
  • 返回为Response对象,低优先级的中间件继续执行process_response()
  • 返回为Request对象,低优先级的中间件中的process_response()则不会调用,产生一个新的请求发送给调度器。
  • 抛出IgnoreRequest异常,交给请求的callback()方法回调。
    3.process_exception返回值为None、Response对象、Request对象之一。
  • 返回为None,低优先级中中间件的process_exception继续调用。
  • 返回为Response对象,低优先级的process_response继续调用。
  • 返回为Request对象,低优先级的中间件不再被调用。产生一个新的请求发送给调度器。
使用

在这里插入图片描述

在上例中,定义了一个中间件。

  • 在process_request方法中,随机返回了请求头。
  • 在process_response方法中,把响应体的状态码302替换成了200。
  • 然后添加到 settings.py
    在这里插入图片描述
scrapy原生下载中间件
    DOWNLOADER_MIDDLEWARES_BASE = {
        # Engine side
        'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
        'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
        'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
        'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
        'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
        'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
        'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
        'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
        'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
        'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
        'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
        'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
        'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
        'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
        # Downloader side
    }

Spider Middleware的用法

下载器把响应体发送给Spider之前以及Spider生成Item或请求之后都会经过Spider Middleware处理。

说明
核心方法

每个中间件都定义了以下一个或四个方法:

  1. process_spide_input(response,spider)
    1. 参数:response - 被处理的响应体,spider - 对应的Spider
    2. 返回值:None或抛出一个异常
      • 返回为None时,继续调用低优先级的中间件。
      • 抛出异常时,低优先级的中间件将不会执行。调用该请求的errback(),errback的输出将会被重新输入到中间件,调用process_spider_output()。
  2. process_spider_output(response,result,spider)
    1. 参数:response - 被处理的响应体,result - 包含请求或者item对象的可迭代对象,也就是Spider的返回值。
    2. 返回值:返回请求或者item的可迭代对象
  3. process_spider_exception(response,exception,spider)
    1. 参数:response - 被处理的响应体,exception - 被抛出的异常,spider - 抛出该异常的spider
    2. 返回值:None或者(包含请求或者item的可迭代对象)
      • 返回为None时,继续调用低优先级的中间处理该异常。
      • 返回为可迭代对象时,调用低优先级的process_spider_output()。
  4. process_start_requests(start_request,spider)
    1. 参数:start_request - 包含请求的可迭代对象,spider - 即Spider对象
    2. 返回值:包含请求的可迭代对象。
使用
    class OffsiteMiddleware:
    
        def __init__(self, stats):
            self.stats = stats
    
        @classmethod
        def from_crawler(cls, crawler):
            o = cls(crawler.stats)
            crawler.signals.connect(o.spider_opened, signal=signals.spider_opened)
            return o
    
        def process_spider_output(self, response, result, spider):
            for x in result:
                if isinstance(x, Request):
                    if x.dont_filter or self.should_follow(x, spider):
                        yield x
                    else:
                        domain = urlparse_cached(x).hostname
                        if domain and domain not in self.domains_seen:
                            self.domains_seen.add(domain)
                            logger.debug(
                                "Filtered offsite request to %(domain)r: %(request)s",
                                {'domain': domain, 'request': x}, extra={'spider': spider})
                            self.stats.inc_value('offsite/domains', spider=spider)
                        self.stats.inc_value('offsite/filtered', spider=spider)
                else:
                    yield x
scrapy原生Spider Middleware
    SPIDER_MIDDLEWARES_BASE = {
        # Engine side
        'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
        'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
        'scrapy.spidermiddlewares.referer.RefererMiddleware': 700,
        'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': 800,
        'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
        # Spider side
    } 

item Pipline的用法

item pipline主要功能:

  • 清理HTML数据
  • 验证爬取数据,检查爬取字段
  • 查重并丢弃重复内容
  • 将爬取结果保存到数据库
核心方法

除了必须要有的process_item之外,还有其余几个比较实用的方法:

  1. open_spider(spider)
  2. close_spider(spider)
  3. from_crawler(cls,crawler)

Scrapy提供了专门处理下载的Pipeline包括文件下载和图片下载。下载文件和图片的原理与抓取页面的原理一样,因此下载过程支持异步和多线程,下载十分高效。

内置的图片下载Pipline
    class ImagesPipeline(FilesPipeline):
        """Abstract pipeline that implement the image thumbnail generation logic
    
        """
    
        MEDIA_NAME = 'image'
    
        # Uppercase attributes kept for backward compatibility with code that subclasses
        # ImagesPipeline. They may be overridden by settings.
        MIN_WIDTH = 0
        MIN_HEIGHT = 0
        EXPIRES = 90
        THUMBS = {}
        DEFAULT_IMAGES_URLS_FIELD = 'image_urls'
        DEFAULT_IMAGES_RESULT_FIELD = 'images'
DEFAULT_IMAGES_URLS_FIELD = 'image_urls'
DEFAULT_IMAGES_RESULT_FIELD = 'images'
        def __init__(self, store_uri, download_func=None, settings=None):
          ......
            if not hasattr(self, "IMAGES_RESULT_FIELD"):
                self.IMAGES_RESULT_FIELD = self.DEFAULT_IMAGES_RESULT_FIELD
            if not hasattr(self, "IMAGES_URLS_FIELD"):
                self.IMAGES_URLS_FIELD = self.DEFAULT_IMAGES_URLS_FIELD
    
            self.images_urls_field = settings.get(
                resolve('IMAGES_URLS_FIELD'),
                self.IMAGES_URLS_FIELD
            )
        def get_media_requests(self, item, info):
            urls = ItemAdapter(item).get(self.images_urls_field, [])
            return [Request(u) for u in urls]

可以看到这个Pipeline会默认读取item中的image_urls字段,并且认为该字段为一个列表。在get_media_requests方法中,遍历image_urls字段并生成一个请求的迭代对象。交给调度器请求。
根据需求可以改写ImagePipline类:

from scrapy import Request
from scrapy.pipelines.images import ImagesPipeline


class ImagesPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        yield Request(item['image_url'])

此处将get_media_requestsg改写为直接取item中image_url字段发起请求。
同理

class ImagesPipeline(ImagesPipeline):
    ... ...
    def file_path(self, request, response=None, info=None, *, item=None):
        url = request.url
        file_name = url.split("/")[-1]
        return file_name

    def item_completed(self, results, item, info):
        images_paths = [x['path'] for ok, x in results if ok]
        if not images_paths:
            item['image_url'] = None
        return item

改写file_path为取图片的链接地址的一部分做文件名。改写item_competed为图片链接请求完成之后,若下载失败则修改item的image_url字段为None。
最后添加到settings.py

ITEM_PIPELINES = {
   'tutorial.pipelines.ImagesPipeline': 301,
   'tutorial.pipelines.ArticlePipeline': 301,
   'tutorial.pipelines.MongoPipeline': 400,
}

Cookies池对接

代理池对接

crawl模板

查看模板
在这里插入图片描述

以模板形式创建spider
scrapy genspider -t crawl china tech.china.com
在这里插入图片描述

rules,爬取属性规则,包含一个或多个Rule对象的列表。每个Rule对爬取网站的动作都做了定义。

定义Rule

针对不同的爬取对象,要实现不同的解析函数。

class ChinaSpider(CrawlSpider):
    name = 'china'
    allowed_domains = ['tech.china.com']
    start_urls = ['http://tech.china.com/articles']

    rules = (
        # Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
        Rule(LinkExtractor(allow='article\/.*\.html', restrict_xpaths='//div[@id="left_side"]//div[@class="com_item"]'),
             callback='parse_item'),
        Rule(LinkExtractor(restrict_xpaths='//div[@id="pageStyle"]//a[contains(text(),"下一页")]'))
    )

    def parse_item(self, response):
        loadder = ChinaLoader(item=NewsItem(), response=response)
        loadder.add_xpath('title', '//h1[@id="chan_newsTtile"]/text()')
        loadder.add_value('content', '新闻内容')
        yield loadder.load_item()

gerapy框架

常用命令

(需要先启动scrapyd服务,需要安装scrapyd库(pip install scrapyd
在这里插入图片描述

  • pip install gerapy
  • gerapy init
  • gerapy migrate
  • gerapy createsuperuser
    • 创建用户
  • gerapy runserver
    在这里插入图片描述
配置主机

在这里插入图片描述

添加项目

在这里插入图片描述

打包项目

在这里插入图片描述

创建任务

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值