关于 scrapy框架 详解

scrapy 是一个纯 Python 编写的异步爬虫框架,具备以下特点:

优势 说明
异步高效 基于 Twisted,非阻塞 IO
模块化 各部分可灵活配置/替换
中间件机制 支持代理、UA、cookie 控制等
强大的解析 内置 XPath、CSS 提取器
自动去重 Scheduler 内部维护请求 fingerprint
可扩展 支持 Redis/MongoDB/Selenium 等集成

适合用于中大型项目,管理多个 Spider 和抓取流程。


一、Scrapy 架构图 & 核心原理

bash 复制代码
        ┌────────────────────────────────────┐
        │           Scrapy Engine 引擎       │
        │   (调度、分发请求与响应的控制中枢)  │
        └────────────────────────────────────┘
                      ▲          ▲
                      │          │
       ┌──────────────┘          └────────────────────┐
       ▼                                               ▼
┌──────────────┐                             ┌─────────────────────┐
│ Scheduler    │                             │  Downloader          │
│ 调度器       │                             │ 下载器(发请求)     │
│ 维护请求队列 │                             └─────────────────────┘
└─────▲────────┘                                       ▲
      │                                                │
      │       ┌─────────────────────────────┐          │
      └──────►│ Downloader Middlewares 下载中间件│◄──────┘
              └─────────────────────────────┘
                          ▲
                          │
                    ┌─────┴───────┐
                    │ Request 请求│
                    └────────────┘
                          │
                          ▼
                    ┌─────────────┐
                    │ Response 响应│
                    └────┬────────┘
                         │
                         ▼
         ┌────────────────────────────────────┐
         │             Spider 爬虫类           │
         │    (处理响应,提取数据和生成新请求) │
         └────────────────┬───────────────────┘
                          │
                          ▼
                ┌────────────────────┐
                │  Item(提取数据)   │
                └───────┬────────────┘
                        ▼
            ┌──────────────────────────┐
            │  Item Pipeline 管道       │
            │(保存数据到文件、数据库等)│
            └──────────────────────────┘

>工作流程步骤解释

  • >1. Spider 生成初始 Request 请求

    • 如**start_urls = ['https://example.com']**

    • 被送到引擎(Engine)

  • >2. Engine 把请求交给 Scheduler 调度器

    • 调度器负责排队请求,避免重复(有去重功能)
  • >3. Engine 从 Scheduler 取一个请求交给 Downloader 下载器

    • Downloader 通过 HTTP 请求抓网页(可带中间件,如代理)
  • >4. Downloader 下载完后返回 Response 给 Engine

  • >5. Engine 把 Response 给 Spider 的 parse() 方法

    • 写的**parse()** 里会提取数据(Item)或继续发送新请求
  • >6. 提取的数据(Item)交给 Pipeline

    • Pipeline 可以把它存储到:文件、MongoDB、MySQL、Elasticsearch 等
  • >7. Spider 产生的新请求(Request)再次送入 Scheduler → 重复上面过程

>模拟完整流程(豆瓣爬虫举例)

假设爬豆瓣 Top250 页:

  • >1. Spider:创建第一个请求**Request("https://movie.douban.com/top250")**

  • **>2.**Scheduler:收下请求排队

  • **>3.**Downloader:请求网站,返回 HTML

  • **>4.**Spider.parse():用 CSS/XPath 抽取电影名、评分

  • >5. 生成 Item:{'title': '肖申克的救赎', 'score': '9.7'}

  • **>6.**Pipeline:保存为 JSON

  • **>7.**如果页面有"下一页",parse() 再 yield 一个 Request(下一页链接),流程继续


二、Scrapy 项目结构

创建项目:

bash 复制代码
scrapy startproject myspider

结构如下:

bash 复制代码
myspider/                      ← Scrapy 项目根目录
├── scrapy.cfg                 ← Scrapy 配置文件(全局入口)
├── myspider/                 ← 项目 Python 包目录(真正的业务逻辑在这)
│   ├── __init__.py            ← 表明这是一个包
│   ├── items.py               ← 定义数据结构(Item 模型)
│   ├── middlewares.py         ← 下载中间件定义(如加代理)
│   ├── pipelines.py           ← 管道:保存数据(文件、数据库)
│   ├── settings.py            ← 项目配置文件(如 headers、限速、并发数)
│   └── spiders/               ← 存放所有 Spider 的目录
│       └── example.py         ← 一个 Spider 示例(爬虫脚本)

2.1 scrapy.cfg(项目运行配置文件)

位置 :根目录
作用:告诉 Scrapy 你要运行哪个项目的设置文件。

内容示例:

bash 复制代码
[settings]
default = myspider.settings   ← 指定 settings.py 的位置

[deploy]
# 用于部署到 scrapyd 时用,不影响本地运行

当运行 **scrapy crawl xxx**命令时,它会先从这个文件找到项目配置。

2.2 myspider/(项目主模块目录)

这是 Scrapy 真正执行的业务模块,其中所有核心逻辑都写在这里。

1)init.py

让 Python 把 myspider/ 识别为模块包,没别的逻辑。

2)items.py:定义数据结构(类似数据表字段)

Scrapy 的数据提取不是直接用字典,而是专门定义一个**Item** 类。

示例:

python 复制代码
import scrapy

class MyspiderItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
    date = scrapy.Field()

在 Spider 中提取数据时用:

python 复制代码
item = MyspiderItem()
item['title'] = ...
item['author'] = ...
yield item

3)middlewares.py:下载中间件(拦截请求与响应)

Scrapy 支持在请求发出前、响应回来后做额外处理,例如:

  • 修改请求头(如 User-Agent)

  • 设置代理

  • 自动重试

  • 伪装成浏览器

示例:

python 复制代码
class RandomUserAgentMiddleware:
    def process_request(self, request, spider):
        request.headers['User-Agent'] = 'YourUserAgent'

在 **settings.py**中启用:

python 复制代码
DOWNLOADER_MIDDLEWARES = {
    'myspider.middlewares.RandomUserAgentMiddleware': 543,
}

4)pipelines.py:数据管道(保存提取到的数据)

Scrapy 提取的数据通过**Item** 传入管道中做进一步处理,比如:

  • 保存到 JSON、CSV

  • 存入数据库(MongoDB、MySQL)

  • 图片下载

示例:

python 复制代码
class JsonWriterPipeline:
    def open_spider(self, spider):
        self.file = open('items.json', 'w', encoding='utf-8')

    def process_item(self, item, spider):
        self.file.write(str(item) + "\n")
        return item

    def close_spider(self, spider):
        self.file.close()

在**settings.py** 启用:

python 复制代码
ITEM_PIPELINES = {
    'myspider.pipelines.JsonWriterPipeline': 300,
}

5)settings.py:Scrapy 项目的配置中心

可以在这里设置:

配置项 作用
ROBOTSTXT_OBEY 是否遵守 robots 协议(开发建议设为 False)
DOWNLOAD_DELAY 下载延迟(防止被封 IP)
CONCURRENT_REQUESTS 最大并发请求数
DEFAULT_REQUEST_HEADERS 请求头设置
ITEM_PIPELINES 设置哪些 pipeline 被启用
DOWNLOADER_MIDDLEWARES 设置中间件

示例片段:

python 复制代码
BOT_NAME = 'myspider'

ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 1
CONCURRENT_REQUESTS = 16

DEFAULT_REQUEST_HEADERS = {
   'User-Agent': 'Mozilla/5.0',
}

ITEM_PIPELINES = {
   'myspider.pipelines.JsonWriterPipeline': 300,
}

6)spiders/:爬虫文件目录(每个爬虫类放一个 .py)

一个 Spider 类 = 一个网站的爬虫逻辑。

示例:

python 复制代码
import scrapy
from myspider.items import MyspiderItem

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

    def parse(self, response):
        for book in response.css('div.book'):
            item = MyspiderItem()
            item['title'] = book.css('h2::text').get()
            item['author'] = book.css('.author::text').get()
            yield item

运行爬虫:

bash 复制代码
scrapy crawl books

2.3 各模块作用表

位置 作用 是否需要改
scrapy.cfg 项目入口配置 一般不改
myspider/__init__.py 标识模块 不改
items.py 定义数据字段 必改
middlewares.py 拦截请求/响应 可选改
pipelines.py 存储 Item 可选改
settings.py 设置并发、延迟等 常用配置项要改
spiders/ 放爬虫脚本 主战场,必须写

三、项目举例

实战目标

  • 抓取 某勾职位接口。

  • 提取字段:

    • 职位名、公司名、城市、薪资、学历、经验、公司规模
  • 自动翻页(1~5页)

  • 保存为 CSV 文件

第一步:创建项目

打开终端:

bash 复制代码
scrapy startproject lagou_spider
cd lagou_spider

第二步:定义字段(items.py

编辑 lagou_spider/lagou_spider/items.py

python 复制代码
import scrapy

class LagouSpiderItem(scrapy.Item):
    position = scrapy.Field()
    company = scrapy.Field()
    salary = scrapy.Field()
    city = scrapy.Field()
    exp = scrapy.Field()
    edu = scrapy.Field()
    company_size = scrapy.Field()

第三步:创建爬虫文件

bash 复制代码
cd lagou_spider/lagou_spider/spiders
touch lagou.py  # Windows 用户用编辑器创建 lagou.py 文件

编辑 lagou.py

python 复制代码
import scrapy
import json
from lagou_spider.items import LagouSpiderItem

class LagouSpider(scrapy.Spider):
    name = 'lagou'
    allowed_domains = ['lagou.com']
    start_urls = ['https://www.lagou.com/jobs/list_python']

    def start_requests(self):
        for page in range(1, 6):  # 抓取前 5 页
            url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
            headers = {
                'Referer': 'https://www.lagou.com/jobs/list_python',
                'User-Agent': 'Mozilla/5.0',
                'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
            }
            data = {
                'first': 'true' if page == 1 else 'false',
                'pn': str(page),
                'kd': 'python'
            }
            yield scrapy.FormRequest(
                url=url,
                formdata=data,
                headers=headers,
                callback=self.parse
            )

    def parse(self, response):
        data = json.loads(response.text)
        jobs = data['content']['positionResult']['result']
        for job in jobs:
            item = LagouSpiderItem()
            item['position'] = job['positionName']
            item['company'] = job['companyFullName']
            item['salary'] = job['salary']
            item['city'] = job['city']
            item['exp'] = job['workYear']
            item['edu'] = job['education']
            item['company_size'] = job['companySize']
            yield item

第四步:配置 pipeline 保存 CSV

编辑**lagou_spider/lagou_spider/pipelines.py:**

python 复制代码
import csv

class CsvPipeline:
    def open_spider(self, spider):
        self.file = open('lagou_jobs.csv', 'w', newline='', encoding='utf-8-sig')
        self.writer = csv.writer(self.file)
        self.writer.writerow(['职位', '公司', '薪资', '城市', '经验', '学历', '公司规模'])

    def process_item(self, item, spider):
        self.writer.writerow([
            item['position'],
            item['company'],
            item['salary'],
            item['city'],
            item['exp'],
            item['edu'],
            item['company_size']
        ])
        return item

    def close_spider(self, spider):
        self.file.close()

第五步:修改配置 settings.py

编辑 lagou_spider/lagou_spider/settings.py,添加或修改:

python 复制代码
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 1.5  # 降低请求频率,防止封 IP
DEFAULT_REQUEST_HEADERS = {
    'User-Agent': 'Mozilla/5.0'
}
ITEM_PIPELINES = {
    'lagou_spider.pipelines.CsvPipeline': 300,
}

第六步:运行爬虫

在终端中运行:

bash 复制代码
scrapy crawl lagou

第七步:查看结果(lagou_jobs.csv)

输出示例(CSV 文件):

职位 公司 薪资 城市 经验 学历 公司规模
Python开发工程师 字节跳动 15k-30k 北京 3-5年 本科 10000人以上
后端Python工程师 腾讯 20k-40k 深圳 5-10年 本科 5000-10000人

项目结构参考

bash 复制代码
lagou_spider/
├── scrapy.cfg
├── lagou_spider/
│   ├── __init__.py
│   ├── items.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders/
│       └── lagou.py

注意事项

问题 说明
某勾有反爬 添加 DOWNLOAD_DELAY,5 页以内一般不封
接口变化 抓的是 JSON 接口,稳定性比页面 HTML 好
抓太多 IP 会被封,建议加代理池后使用
数据为空 设置 Referer + UA + Content-Type 后就正常了

后续可拓展功能

功能 方法
添加代理池 中间件 process_request() 设置
分布式 scrapy-redis 实现
存 MongoDB 改 pipeline 用 pymongo 写入
接入前端展示 输出 JSON/数据库配合前端页面展示
相关推荐
失败又激情的man3 天前
Scrapy进阶封装(第四阶段:中间件设置,动态UA,ip代理池)
爬虫·scrapy·中间件
Blue桃之夭夭18 天前
Python爬虫(六):Scrapy框架
爬虫·python·scrapy
华科云商xiao徐1 个月前
Python利用Scrapy框架部署分布式爬虫
python·scrapy
cooldream20091 个月前
利用 Scrapy 构建高效网页爬虫:框架解析与实战流程
爬虫·scrapy·架构
一个天蝎座 白勺 程序猿1 个月前
Python爬虫(48)基于Scrapy-Redis与深度强化学习的智能分布式爬虫架构设计与实践
爬虫·python·scrapy
JHC0000001 个月前
重拾Scrapy框架
scrapy
myt20001 个月前
关于scrapy在pycharm中run可以运行,但是debug不行的问题
scrapy·pycharm
_一路向北_1 个月前
爬虫框架:scrapy使用心得
爬虫·scrapy
一个天蝎座 白勺 程序猿1 个月前
Python爬虫(32)Python爬虫高阶:动态页面处理与Scrapy+Selenium+BeautifulSoup分布式架构深度解析实战
爬虫·python·selenium·scrapy·beautifulsoup