pin_drop当前位置:知识文库 ❯ 图文

Scrapy Spider编写 - 掌握爬虫核心采集逻辑教程

一、Spider概述

Spider是Scrapy中定义采集逻辑的核心类,继承自scrapy.Spider。Spider定义了如何爬取某个网站,包括起始URL、页面解析逻辑、跟进链接等。通过编写parse()方法处理响应,使用CSS选择器或XPath提取数据,yield Item或Request实现数据采集和链接跟进。

Spider是整个Scrapy框架中最贴近业务逻辑的部分。你可以通过Scrapy内置的多种Spider类型来适配不同场景,如基础的Spider、支持规则匹配的CrawlSpider、以及支持站点地图的SitemapSpider。更多详情可参考 Scrapy Spider官方文档


二、Spider基本语法

以下是一个最基本的Spider类结构:

代码示例

import scrapy

class MySpider(scrapy.Spider):
    name = 'my_spider'
    allowed_domains = ['example.com']
    start_urls = ['https://example.com']

    def parse(self, response):
        # 提取数据
        yield {...}
        # 跟进链接
        yield scrapy.Request(url, callback=self.parse_detail)

这个结构包含了Spider最基本的三个属性:name(爬虫名称)、allowed_domains(允许爬取的域名)和start_urls(起始URL列表),以及一个必须实现的parse()方法。


三、参数详解

Spider核心属性

属性 类型 必填 说明
name str 爬虫唯一名称,用于scrapy crawl命令调用
allowed_domains list 允许的域名列表,超出域名的请求将被过滤
start_urls list 起始URL列表,默认由start_requests()方法读取
custom_settings dict 爬虫专属配置,覆盖settings.py中的全局设置

Spider核心方法

方法 说明
start_requests() 生成初始请求,默认读取start_urls
parse(response) 解析响应,必须实现
closed(reason) 爬虫关闭时调用,可做清理工作

Request参数

参数 类型 必填 说明
url str 请求URL
callback callable 回调函数,默认parse
method str HTTP方法,默认GET
headers dict 请求头
meta dict 请求元数据,用于在请求间传递数据
dont_filter bool 是否过滤重复URL,默认False(过滤)

四、返回值说明

parse()方法通过yield返回两种类型的数据:

  • Item字典:包含提取到的结构化数据,如yield {'title': '标题', 'url': '链接'},将传递给Pipeline处理。

  • scrapy.Request对象:包含新的请求URL和回调函数,用于跟进链接实现多级爬取。

同一个parse()方法中既可以yield Item也可以yield Request,Scrapy会自动区分处理。这是Scrapy实现"列表页提取+跟进详情页"模式的核心机制。


五、代码示例

示例1:基本Spider

以下是一个爬取 quotes.toscrape.com 网站名言的基本Spider:

代码示例

import scrapy

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['https://quotes.toscrape.com/']

    def parse(self, response):
        # 使用CSS选择器提取数据
        quotes = response.css('div.quote')

        for quote in quotes:
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

运行命令:

代码示例

scrapy crawl quotes -o quotes.json

说明:response.css('div.quote') 选取所有名言容器,::text 提取文本内容,.get() 获取第一个匹配,.getall() 获取所有匹配列表。

示例2:自定义start_requests

当需要自定义初始请求(如添加特殊Header、传递meta数据)时,可以重写start_requests()方法:

代码示例

import scrapy

class LoginSpider(scrapy.Spider):
    name = 'login_spider'

    def start_requests(self):
        """自定义初始请求"""
        urls = [
            'https://example.com/page1',
            'https://example.com/page2',
        ]
        for url in urls:
            yield scrapy.Request(
                url=url,
                callback=self.parse,
                headers={'Custom-Header': 'value'},
                meta={'page': url.split('/')[-1]},
            )

    def parse(self, response):
        page = response.meta.get('page')
        self.logger.info(f'解析页面: {page}')
        yield {
            'page': page,
            'title': response.css('title::text').get(),
        }

通过meta字典可以在请求之间传递数据,在回调函数中通过response.meta获取。这是多级爬取时保持上下文的关键方式。

示例3:多级页面爬取

以下Spider实现了从列表页提取数据,并跟进到作者详情页获取更多信息的多级爬取:

代码示例

import scrapy

class MultiLevelSpider(scrapy.Spider):
    name = 'multi_level'
    start_urls = ['https://quotes.toscrape.com/']

    def parse(self, response):
        """第一级:列表页"""
        quotes = response.css('div.quote')

        for quote in quotes:
            author_url = quote.css('small.author + a::attr(href)').get()
            if author_url:
                yield scrapy.Request(
                    url=response.urljoin(author_url),
                    callback=self.parse_author,
                    meta={'quote_text': quote.css('span.text::text').get()},
                )

        # 跟进下一页
        next_page = response.css('li.next a::attr(href)').get()
        if next_page:
            yield scrapy.Request(
                url=response.urljoin(next_page),
                callback=self.parse,
            )

    def parse_author(self, response):
        """第二级:详情页"""
        yield {
            'quote': response.meta['quote_text'],
            'author': response.css('h3.author-title::text').get(),
            'born': response.css('span.author-born-date::text').get(),
        }

关键技术点:response.urljoin() 将相对URL转换为绝对URL;callback=self.parse_author 指定新的回调函数处理详情页;meta 将列表页提取的名言文本传递到详情页回调函数中。

小贴士

对于更复杂的多页爬取场景,Scrapy提供了CrawlSpider类,配合RuleLinkExtractor可以自动跟进链接,无需手动编写跟进逻辑。适合规则明确的整站爬取场景。


六、实际应用场景

  • 列表页+详情页的多级爬取:电商网站商品列表页提取商品链接,跟进到详情页获取价格、描述、评价等完整信息。

  • 需要登录认证的网站爬取:通过start_requests()发送POST请求登录,使用FormRequest处理表单提交,保持Session状态。

  • 多入口URL的批量采集:从多个起始URL同时开始采集,如多个分类页面、多个城市的站点等。


七、注意事项

name唯一性:name属性必须唯一,同一项目中不能有重名爬虫。Scrapy通过name来识别和运行特定爬虫。

allowed_domains过滤:allowed_domains会过滤非目标域名的请求,设置不当可能导致请求被忽略。如果爬虫需要跨域请求,请确保将相关域名都添加到列表中。

URL去重:Scrapy默认会过滤重复URL,设置dont_filter=True可禁用此行为。适用于需要重复访问同一URL的场景(如实时监控)。

yield vs return:parse()方法必须使用yield而非return返回数据。yield是生成器语法,允许函数在运行过程中逐步产出数据,这对于异步框架的流量控制至关重要。


八、数据提取方式对比

Scrapy支持多种数据提取方式,各有优缺点:

方式 示例代码 特点
CSS选择器 response.css('h1::text') 简洁直观,前端开发者友好,适合常规结构
XPath response.xpath('//h1/text()') 功能强大,支持复杂查询和轴定位
正则表达式 response.re(r'pattern') 灵活强大,适合非结构化文本提取

实际开发中,CSS选择器是最常用的方式,语法简洁且性能良好。XPath在需要复杂定位(如查找父元素、兄弟元素)时更有优势。正则表达式主要用于从文本内容中提取特定模式的数据。


九、小结与练习题

本节小结

  • 基本结构:Spider继承scrapy.Spider,必须定义name属性和parse()方法。

  • 请求定制:start_urls定义起始URL,也可重写start_requests()自定义初始请求。

  • 数据返回:通过yield返回Item字典或Request对象,实现数据采集和链接跟进。

  • 数据传递:使用meta字典在请求间传递数据,是多级爬取的核心技术。

练习题

练习1

编写一个Spider,爬取quotes.toscrape.com的名言列表,提取名言文本、作者和标签,并保存到JSON文件。

练习2

编写一个Spider,重写start_requests()方法,使用POST请求提交表单数据到测试网站,并获取响应结果。

常见问题

CSS选择器和XPath应该选择哪个?

两者在Scrapy中性能基本一致。CSS选择器语法更简洁,适合大多数常规提取场景;XPath功能更强大,支持向上查找父元素、复杂的轴定位等。建议优先使用CSS选择器,在CSS无法表达的复杂场景下再使用XPath。

为什么parse()方法必须用yield而不是return?

yield是Python生成器语法,允许函数在运行过程中逐步产出数据而不终止。Scrapy利用这一特性实现异步流量控制:当框架繁忙时会暂停生成器,空闲时继续产出。如果使用return,只能返回一次数据,无法实现这种流量控制机制。

如何在Spider中使用自定义配置覆盖全局设置?

在Spider类中定义custom_settings字典即可。例如:custom_settings = {'DOWNLOAD_DELAY': 2, 'CONCURRENT_REQUESTS': 8}。这些设置只对该Spider生效,不会影响项目中的其他爬虫。

如何实现翻页爬取?

在parse()方法中提取下一页链接,使用response.urljoin()转换为绝对URL,然后yield一个scrapy.Request对象,callback指向parse自身。参考示例3中的翻页逻辑:next_page = response.css('li.next a::attr(href)').get(),然后yield scrapy.Request(url=response.urljoin(next_page), callback=self.parse)。

Spider中的self.logger是什么?

self.logger是Scrapy自动为Spider创建的日志记录器。可以使用self.logger.info()、self.logger.warning()、self.logger.error()等方法记录日志。日志输出会被Scrapy的日志系统统一管理,可以配置输出到文件或控制台。

标签: Spider编写 CSS选择器 XPath 多级爬取 Scrapy教程 数据提取 parse方法

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Scrapy项目创建 - 从零搭建爬虫项目完整指南 下一篇: Scrapy Item定义 - 结构化数据采集容器详解教程

poll相关推荐