Day 25 25.1 Scrapy框架之全站爬虫(CrawlSpider)

发布时间 2023-04-20 09:43:13作者: Chimengmeng

Scrapy框架之全站爬虫(CrawlSpider)

  • 在之前 Scrapy 的基本使用当中,spider 如果要重新发送请求的话,就需要自己解析页面,然后发送请求。
  • 而 CrawlSpider 则可以通过设置 url 条件自动发送请求。

LinkExtractors

  • CrawlSpider 是 Spider 的一个派生类。
    • CrawlSpider 与 spider 不同的是就在于下一次请求的 url 不需要自己手动解析,而这一点则是通过 LinkExtractors 实现的。
  • LinkExtractor类的构造方法如下所示。
class scrapy.linkextractors.LinkExtractor(
    allow = (),
    deny = (),
    allow_domains = (),
    deny_domains = (),
    restrict_xpaths = (),
    tags = ('a','area'),
    attrs = ('href'),
    canonicalize = False,
    unique = True,
    process_value = None,
    deny_extensions = None,
    restrict_css=(),
   strip=True
)
  • 其中的参数为:
allow:允许的 url。所有满足这个正则表达式的 url 都会被提取
deny:禁止的 url。所有满足这个正则表达式的 url 都不会被提取
allow_domains:允许的域名。只有在这个里面指定的域名的 url 才会被提取
deny_domains:禁止的域名。所有在这个里面指定的域名的 url 都不会被提取
restrict_xpaths:严格的 xpath。和 allow 共同过滤链接

tags:接收一个标签或标签列表,提取标签内的列表,默认为[‘a’, ‘area’]
attrs:接收一个属性或属性列表,提取指定属性内的链接,默认为[‘href’]

Rule

  • LinkExtractors 需要传递到 Rule 类对象中才能发挥作用。
    • Rule 类常见的参数为:
link_extractors:是一个LinkExtractor对象,用于定义需要提取的链接

callback:从link_extractor中没获取链接时,参数所制定的值作为回调函数,该回调函数接受一个response作为起第一个参数
注意:当编写爬虫规则是,避免使用parse作为回调函数。由于CrawlSpider使用parse方法来实现其逻辑,如果覆盖了parse方法,CrawlSpider将会运行失败

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

process_links:指定该Spider中那个的函数将会被调用,从link_extractor中获取到链接列表是将会调用该函数。该方法主要用来过滤
process_request:指定该Spider中那个的函数将会被调用,该规则提取到每个request是都会调用该函数。(用来过滤request)

  • 除了上述的这些差别,Crawlspider 和 spider 基本没有什么差别了。

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(需要自定义)处理响应。

全站爬虫案例

  • 创建项目:
scrapy startproject imgPro
cd imgPro
scrapy genspider img
  • spider.img.py
# -*- coding: utf-8 -*-
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
import os


class ImgSpider(CrawlSpider):
    name = 'img'

    # allowed_domains = ["netbian.com"]

    start_urls = ['http://www.daimg.com/pic/%E7%BE%8E%E5%A5%B3%E5%9B%BE%E7%89%87-0-0-0-0-0_1.html']

    link = LinkExtractor(tags=['img'], attrs='src', deny_extensions=[''], )
    link2 = LinkExtractor(allow=r'pic/%E7%BE%8E%E5%A5%B3%E5%9B%BE%E7%89%87')
    rules = (
        Rule(link, callback="parse_item", follow=False, ),
        Rule(link2, follow=True),
    )

    def parse_item(self, response):
        p = os.path.join("imgs", os.path.basename(response.url))
        with open(p, 'wb') as f:
            f.write(response.body)
        print(f"{p}下载完成!")
  • 注意事项:
  1. crawlspider爬虫默认继承了CrawlSpider类。
  2. parse_item表示crawlspider爬虫的数据提取函数,在crawlspider爬虫中不能编写parse函数。parse函数是普通类独有的。
  3. rules是元组类型,小括号后面必须加逗号","
  4. scrapy genspider -t crawl 爬虫名可以直接生成CrawlSpider结构的模板代码