位置: 文档库 > Python > Scrapy爬虫入门教程四 Spider(爬虫)

Scrapy爬虫入门教程四 Spider(爬虫)

IronMyth 上传于 2020-10-17 02:49

《Scrapy爬虫入门教程四 Spider(爬虫)》

在Scrapy框架中,Spider(爬虫)是核心组件之一,负责定义爬取逻辑、解析响应数据并生成新的请求。本教程将系统讲解Spider的创建方法、常用属性、内置方法以及实战案例,帮助读者快速掌握Scrapy爬虫的开发技巧。

一、Spider基础概念

Spider是Scrapy中用于定义爬取行为的类,每个Spider必须继承自`scrapy.Spider`基类。一个完整的Spider需要包含以下核心要素:

  • name:唯一标识爬虫的名称
  • start_urls:初始请求的URL列表
  • parse:默认的响应解析方法

创建Spider的基本步骤如下:

# 在spiders目录下创建example_spider.py
import scrapy

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

    def parse(self, response):
        # 解析逻辑
        pass

二、Spider核心属性详解

1. name属性

name是Spider的唯一标识符,用于在命令行中指定运行的爬虫:

scrapy crawl example  # 运行名为example的爬虫

命名规范建议使用小写字母和下划线,避免使用空格和特殊字符。

2. allowed_domains与start_urls

allowed_domains限制爬虫只能在指定域名下爬取:

class RestrictedSpider(scrapy.Spider):
    name = 'restricted'
    allowed_domains = ['example.com']
    start_urls = ['https://example.com/page1']

start_urls定义初始请求的URL列表,支持相对路径(需配合`http://`或`https://`前缀)。

3. custom_settings

覆盖项目级设置的Spider专属配置:

class CustomSettingsSpider(scrapy.Spider):
    name = 'custom_settings'
    custom_settings = {
        'USER_AGENT': 'MyCustomBot/1.0',
        'DOWNLOAD_DELAY': 2
    }

三、Spider方法解析

1. parse方法

默认的响应处理函数,接收`response`对象作为参数:

def parse(self, response):
    # 提取数据示例
    title = response.css('h1::text').get()
    yield {'title': title}

    # 生成新请求示例
    for href in response.css('a::attr(href)').getall():
        yield response.follow(href, self.parse)

2. 生成请求的三种方式

方式1:scrapy.Request

yield scrapy.Request(
    url='https://example.com/next',
    callback=self.parse_next,
    meta={'key': 'value'}  # 传递额外数据
)

方式2:response.follow(推荐)

for link in response.css('a::attr(href)').getall():
    yield response.follow(link, callback=self.parse_detail)

方式3:response.follow_all(批量处理)

yield from response.follow_all(
    css='div.item a::attr(href)',
    callback=self.parse_item
)

3. 错误处理机制

通过`errback`参数处理请求失败:

def parse(self, response):
    yield scrapy.Request(
        url='https://example.com/fail',
        errback=self.handle_error
    )

def handle_error(self, failure):
    self.logger.error(f'Request failed: {failure.request.url}')

四、Spider进阶技巧

1. 多Spider协作

通过`CrawlSpider`实现规则化爬取:

from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MultiSpider(CrawlSpider):
    name = 'multi'
    allowed_domains = ['example.com']
    start_urls = ['https://example.com']

    rules = (
        Rule(LinkExtractor(allow=r'/page/\d+'), callback='parse_page'),
        Rule(LinkExtractor(allow=r'/item/\d+'), callback='parse_item')
    )

    def parse_page(self, response):
        # 处理页面
        pass

    def parse_item(self, response):
        # 处理详情页
        pass

2. 动态生成Spider

使用`SpiderLoader`动态加载爬虫:

from scrapy.spiderloader import SpiderLoader

loader = SpiderLoader.from_settings(settings)
spider_classes = loader.list()  # 获取所有爬虫类

3. 中间件集成

在Spider中覆盖中间件行为:

class MiddlewareSpider(scrapy.Spider):
    name = 'middleware'

    def close(self, reason):
        # 爬虫结束时的清理工作
        pass

    def spider_opened(self, spider):
        # 爬虫启动时的初始化
        pass

五、实战案例:豆瓣电影Top250

完整实现爬取豆瓣电影Top250的Spider:

import scrapy

class DoubanSpider(scrapy.Spider):
    name = 'douban'
    allowed_domains = ['movie.douban.com']
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        # 解析电影列表
        for movie in response.css('.item'):
            yield {
                'rank': movie.css('.pic em::text').get(),
                'title': movie.css('.title::text').get(),
                'rating': movie.css('.rating_num::text').get(),
                'year': movie.css('.bd p:nth-child(1)').re_first(r'\d{4}')
            }

        # 翻页处理
        next_page = response.css('.next a::attr(href)').get()
        if next_page:
            yield response.follow(next_page, self.parse)

运行配置

1. 创建`settings.py`配置:

BOT_NAME = 'douban_spider'
SPIDER_MODULES = ['douban_spider.spiders']
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
ROBOTSTXT_OBEY = False

2. 启动命令:

scrapy crawl douban -o movies.json

六、常见问题解决方案

1. 请求被屏蔽

解决方案:

  • 设置随机User-Agent
  • 使用代理IP池
  • 降低下载延迟
class SafeSpider(scrapy.Spider):
    name = 'safe'
    custom_settings = {
        'DOWNLOAD_DELAY': 3,
        'USER_AGENT_LIST': ['agent1', 'agent2'],
        'ROTATING_PROXY_LIST': ['proxy1:port', 'proxy2:port']
    }

2. 动态内容加载

处理AJAX请求的两种方式:

  1. 分析API接口直接请求
  2. 使用Selenium模拟浏览器
# 示例:直接请求API
class ApiSpider(scrapy.Spider):
    name = 'api'
    start_urls = ['https://api.example.com/data?page=1']

    def parse(self, response):
        data = response.json()
        # 处理JSON数据

3. 数据去重策略

Scrapy内置的去重机制:

class DeduplicateSpider(scrapy.Spider):
    name = 'dedup'
    custom_settings = {
        'DUPEFILTER_CLASS': 'scrapy.dupefilters.RFPDupeFilter',
        'DUPEFILTER_DEBUG': True
    }

七、最佳实践建议

1. 遵循DRY原则,将公共逻辑提取到BaseSpider

class BaseSpider(scrapy.Spider):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.common_header = {'Referer': 'https://example.com'}

class ChildSpider(BaseSpider):
    name = 'child'

2. 使用ItemLoader处理复杂数据结构

from scrapy.loader import ItemLoader
from itemloaders.processors import TakeFirst, MapCompose

class MovieLoader(ItemLoader):
    default_output_processor = TakeFirst()

    def year_processor(self, values):
        return [v.strip() for v in values if v.isdigit()]

3. 日志分级管理

import logging

class LogSpider(scrapy.Spider):
    name = 'log'

    def parse(self, response):
        self.logger.debug('Debug message')
        self.logger.info('Info message')
        self.logger.warning('Warning message')

八、总结与扩展

通过本教程的学习,读者应掌握以下核心技能:

  • 创建基础Spider并配置核心属性
  • 使用parse方法处理响应数据
  • 生成和管理请求的三种方式
  • 实现多Spider协作和动态爬取
  • 解决常见反爬机制

扩展学习方向:

  1. 分布式爬虫(Scrapy-Redis)
  2. Scrapy与Django/Flask集成
  3. 爬虫性能优化技巧
  4. 机器学习辅助爬虫开发

关键词:Scrapy、Spider爬虫Python网络爬虫、响应解析、请求生成反爬机制数据提取、CrawlSpider、动态爬取

简介:本文系统讲解Scrapy框架中Spider组件的核心概念与实战技巧,涵盖属性配置、方法解析、进阶功能及完整案例,帮助开发者掌握从基础爬虫创建到复杂场景实现的完整流程。