python--爬虫--成熟的爬虫框架Scrapy

一、为什么要用Scrapy?

在大数据时代,数据就是企业的核心资产。而获取外部数据最直接的方式之一,就是爬虫。目前主流的爬虫技术有很多:基于C++的Larbin、基于Java的Webmagic和Nutch、基于Golang的Pholcus,以及今天要重点介绍的------基于Python的Scrapy

那么问题来了:为什么选Scrapy?

简单来说,Scrapy是一个为了爬取网站数据、提取结构性数据而编写的应用框架 ,可以应用在数据挖掘、信息处理或存储历史数据等一系列场景中。它底层基于Twisted异步网络框架,并发能力非常强悍。

举个直观的例子:假设目标网站每页有500个条目,Scrapy可以同时发起20个请求,每个请求耗时1秒,那么每秒就能拿到10000个条目 。如果要将这些数据存储到云端(每个存储操作耗时3秒),就需要同时处理30000个写入请求。传统的多线程方案需要创建30000个线程,系统根本无法承载,但Scrapy基于异步机制,只要硬件够,30000个并发轻松搞定

这就是Scrapy最核心的竞争力------高吞吐量

二、Scrapy能做什么?

有了这个利器,你可以做的事情太多了:

  • 舆情监测:获取互联网数据,监测舆论动向,评估事态发展
  • 热点发现:监测新闻的转发、评论增量趋势,发现潜在热点
  • 金融分析:抓取大V调仓记录、上市公司年报,辅助投资决策
  • 房产分析:获取交易、价格数据,分析市场走势

关于反爬虫:大部分情况下,反爬虫需求不会影响到网站的正常使用。爬虫可以伪装成正常用户,只是增加了一些代价而已。只要人能正常访问的网页,爬虫在具备同等资源下就一定能抓取。

三、Scrapy架构概览

Scrapy采用组件化设计,各模块间松耦合,便于扩展和定制。

复制代码
┌─────────────────────────────────────────────────────┐
│                    Scrapy Engine                    │
│                      (引擎)                         │
│   ┌──────────┐  ┌──────────┐  ┌──────────────┐    │
│   │Scheduler │  │Downloader│  │   Spiders    │    │
│   │ (调度器) │  │ (下载器) │  │   (爬虫)     │    │
│   └──────────┘  └──────────┘  └──────────────┘    │
│        ↑              ↑              ↑              │
│   ┌──────────────────────────────────────────┐     │
│   │      Item Pipeline (项目管道)            │     │
│   │      (数据清洗、验证、存储)              │     │
│   └──────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────┘

核心组件说明:

组件 职责
Engine(引擎) 控制所有组件间的数据流,触发事件
Scheduler(调度器) 接收请求并排队,去重,按需返回给引擎
Downloader(下载器) 下载网页内容,返回响应
Spiders(爬虫) 用户编写的解析逻辑,提取数据和新的URL
Item Pipeline(管道) 数据处理:清洗、验证、存数据库
Middlewares(中间件) 处理请求/响应的钩子,可扩展代理、UA等

数据流转过程:

  1. 引擎从Spider获取初始请求
  2. 引擎将请求交给调度器排队
  3. 调度器返回下一个请求给引擎
  4. 引擎通过下载器中间件把请求发给下载器
  5. 下载器完成下载,返回响应给引擎
  6. 引擎通过爬虫中间件把响应发给Spider处理
  7. Spider解析响应,产出Item和新的Request
  8. 引擎把Item交给Pipeline处理,把新Request交给调度器
  9. 重复上述过程,直到没有更多请求

四、快速上手

4.1 安装

bash 复制代码
pip install scrapy
# 或使用国内镜像加速
pip install scrapy -i https://pypi.douban.com/simple

# 验证安装
scrapy version

Windows用户注意:可能需要先安装Microsoft Visual C++ Build Tools来解决依赖包编译问题。

4.2 创建项目

bash 复制代码
scrapy startproject tutorial

生成的项目结构:

复制代码
tutorial/
    scrapy.cfg            # 部署配置文件
    tutorial/
        __init__.py
        items.py          # 数据模型定义
        pipelines.py      # 数据处理管道
        settings.py       # 项目配置
        spiders/          # 爬虫目录
            __init__.py

4.3 编写第一个爬虫

spiders/quotes_spider.py 中创建爬虫类:

python 复制代码
import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"  # 爬虫唯一标识
    
    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)
    
    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = f'quotes-{page}.html'
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log(f'Saved file {filename}')

4.4 运行爬虫

bash 复制代码
# 进入项目根目录
cd tutorial
# 执行爬虫
scrapy crawl quotes

执行后,你会看到生成了 quotes-1.htmlquotes-2.html 两个文件。

五、数据提取:选择器

Scrapy提供了两种强大的数据提取方式:CSS选择器XPath

5.1 交互式Shell调试

先用Shell测试选择器是否正确:

bash 复制代码
scrapy shell 'http://quotes.toscrape.com/page/1/'

5.2 CSS选择器示例

python 复制代码
# 提取标题
response.css('title::text').get()  # 'Quotes to Scrape'

# 提取单个元素
response.css('span.text::text').get()

# 提取多个元素
response.css('div.tags a.tag::text').getall()

# 提取属性
response.css('li.next a::attr(href)').get()

注意::text::attr(name) 是Scrapy扩展的伪元素,标准CSS不支持,但爬虫场景非常实用。

5.3 XPath选择器示例

python 复制代码
response.xpath('//title/text()').get()
response.xpath('//div[@class="quote"]/span/text()').getall()
response.xpath('//a/@href').getall()

XPath功能更强大,可以基于内容进行选择,推荐深入学习。

六、完整示例:爬取名言网站

6.1 定义数据结构(items.py

python 复制代码
import scrapy

class QuoteItem(scrapy.Item):
    text = scrapy.Field()      # 名言内容
    author = scrapy.Field()    # 作者
    tags = scrapy.Field()      # 标签列表

6.2 编写爬虫(spiders/quotes_spider.py)

python 复制代码
import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = ['http://quotes.toscrape.com/page/1/']
    
    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }
        
        # 翻页处理
        next_page = response.css('li.next a::attr(href)').get()
        if next_page:
            yield scrapy.Request(
                response.urljoin(next_page),
                callback=self.parse
            )

6.3 数据存储

方式一:直接导出(最简单)

bash 复制代码
scrapy crawl quotes -o quotes.json
# 或导出为JSON Lines格式
scrapy crawl quotes -o quotes.jl

注意 :Scrapy默认会追加到已有文件而非覆盖,重复运行会生成损坏的JSON文件。建议使用 .jl 格式(每行一个JSON对象)。

方式二:自定义Pipeline(更灵活)

pipelines.py 中实现数据清洗和存储:

python 复制代码
import json
from itemadapter import ItemAdapter

class JsonWriterPipeline:
    def open_spider(self, spider):
        self.file = open('items.jsonl', 'w')
    
    def close_spider(self, spider):
        self.file.close()
    
    def process_item(self, item, spider):
        line = json.dumps(ItemAdapter(item).asdict()) + "\n"
        self.file.write(line)
        return item

然后在 settings.py 中启用管道:

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

数值(300)决定了执行顺序,数字越小越先执行,通常定义在0-1000范围。

七、进阶技巧

7.1 爬虫参数

通过 -a 传递参数给爬虫:

bash 复制代码
scrapy crawl quotes -a tag=humor

在爬虫中通过 self.tag 获取:

python 复制代码
def start_requests(self):
    url = 'http://quotes.toscrape.com/'
    tag = getattr(self, 'tag', None)
    if tag:
        url = f'{url}tag/{tag}'
    yield scrapy.Request(url, self.parse)

7.2 关键配置(settings.py

python 复制代码
# 禁用robots.txt(需谨慎)
ROBOTSTXT_OBEY = False

# 请求间隔(防封)
DOWNLOAD_DELAY = 2

# 伪装User-Agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'

# 自动限速
AUTOTHROTTLE_ENABLED = True

# 并发控制
CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 8

7.3 遇到动态加载内容怎么办?

对于JavaScript渲染的页面,可以结合 SplashSelenium。以Splash为例:

bash 复制代码
pip install scrapy-splash

配置中间件使用Splash渲染:

python 复制代码
SPLASH_URL = 'http://localhost:8050'
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
}

八、总结

Scrapy的核心优势在于:

  1. 高性能:基于Twisted异步框架,并发能力强
  2. 模块化:组件松耦合,便于扩展
  3. 开箱即用:内置选择器、中间件、导出等功能
  4. 社区活跃:遇到问题容易找到解决方案

记住:只要人能访问的网页,爬虫在同等资源下就一定能抓取。

相关推荐
Pluchon1 小时前
Java个人综合项目——萌部落社区V2.0
java·python·spring·spring cloud·postman·idea
不瘦80斤不改名2 小时前
01-vibe-coding-起源与本质
人工智能·python
夜雪一千2 小时前
如何对新闻数据进行模糊去重
python
oyguyteggytrrwwwrt4 小时前
3dgs渲染部分详细注释
python
天天爱吃肉82186 小时前
【重磅发布:拿下新超仁达代理权 】
大数据·人工智能·python·功能测试·汽车
神王宝宝 王者小学6 小时前
面向领域驱动架构的查询实现方式
前端·python·架构
ningmengjing_7 小时前
Redis 从入门到实战:Python操作全攻略
数据库·redis·python
️学习的小王7 小时前
智能文档助手:基于RAG的本地化文档问答系统实战指南
人工智能·python·机器学习
不瘦80斤不改名7 小时前
05-vibe-coding-向agentic-engineering演进
人工智能·笔记·python·prompt