Home » Python » Python爬虫:Scrapy框架详解与实战指南

Python爬虫:Scrapy框架详解与实战指南

·

在当今数字化时代,网络爬虫技术已成为数据获取的重要手段。Python凭借其简洁的语法和丰富的生态系统,成为网络爬虫开发的首选语言。在众多Python爬虫工具中,Scrapy作为一个强大的爬虫框架,以其高性能、可扩展性和易用性著称,深受开发者青睐。

Scrapy框架概述

Scrapy是一个基于Twisted异步网络框架开发的爬虫框架,专门用于大规模网页数据提取。它采用事件驱动的网络编程模式,能够高效处理并发请求,是构建网络爬虫的理想选择。

主要特点:

  1. 异步网络请求:基于Twisted框架,支持异步I/O,大幅提升爬取效率
  2. 中间件系统:可自定义处理请求和响应的中间件,实现更灵活的数据处理
  3. 内置Pipeline:支持数据清洗、验证和存储的管道机制
  4. 分布式支持:可通过Redis等组件实现分布式爬取
  5. 自动重试:智能处理请求失败的情况
  6. 导出多种格式:支持JSON、CSV、XML等多种数据导出格式

安装与环境配置

首先,我们需要安装Scrapy框架。推荐使用pip包管理器进行安装:

pip install scrapy

对于Windows用户,可能需要先安装一些依赖:

pip install pywin32
pip install twisted

Scrapy项目结构

创建一个新的Scrapy项目:

scrapy startproject tutorial
cd tutorial

这会生成如下项目结构:

tutorial/
    ├── scrapy.cfg            # 项目配置文件
    └── tutorial/             # 项目Python模块
        ├── __init__.py
        ├── items.py          # 项目项目定义
        ├── middlewares.py    # 中间件定义
        ├── pipelines.py      # 管道文件
        ├── settings.py       # 设置文件
        └── spiders/         # 放置spider代码的目录
            └── __init__.py

实战示例:构建图书信息爬虫

让我们以爬取某在线书店的图书信息为例,展示Scrapy的使用方法。

第一步:定义数据模型

items.py中定义要抓取的数据结构:

import scrapy

class BookItem(scrapy.Item):
    title = scrapy.Field()        # 书名
    author = scrapy.Field()       # 作者
    price = scrapy.Field()        # 价格
    description = scrapy.Field()  # 描述
    isbn = scrapy.Field()         # ISBN号

第二步:创建爬虫

spiders目录下创建新文件books_spider.py

import scrapy
from tutorial.items import BookItem

class BooksSpider(scrapy.Spider):
    name = 'books'  # 爬虫的唯一标识
    # 这里使用示例网站,实际使用时请替换为目标网站
    start_urls = ['http://books.toscrape.com/']
    
    def parse(self, response):
        # 获取每本书的链接
        for book in response.css('article.product_pod'):
            book_url = book.css('h3 a::attr(href)').get()
            yield response.follow(book_url, self.parse_book)
            
        # 处理下一页
        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)
    
    def parse_book(self, response):
        book = BookItem()
        book['title'] = response.css('h1::text').get()
        book['price'] = response.css('p.price_color::text').get()
        book['description'] = response.css('#product_description + p::text').get()
        # 提取表格中的信息
        rows = response.css('table tr')
        for row in rows:
            heading = row.css('th::text').get()
            if heading == 'Author':
                book['author'] = row.css('td::text').get()
            elif heading == 'ISBN':
                book['isbn'] = row.css('td::text').get()
        yield book

第三步:配置数据处理管道

pipelines.py中添加数据处理逻辑:

import json

class JsonWriterPipeline:
    def open_spider(self, spider):
        self.file = open('books.json', 'w')

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

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

第四步:配置设置

settings.py中启用管道:

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

# 添加请求头,模拟浏览器行为
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'

# 控制请求延迟,避免对服务器造成压力
DOWNLOAD_DELAY = 1

第五步:运行爬虫

在项目根目录下执行:

scrapy crawl books

高级功能展示

1. 使用中间件处理请求

class CustomUserAgentMiddleware:
    def process_request(self, request, spider):
        user_agents = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...',
            'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) ...'
        ]
        request.headers['User-Agent'] = random.choice(user_agents)

2. 实现图片下载

from scrapy.pipelines.images import ImagesPipeline

class BookImagePipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        if item['image_url']:
            yield scrapy.Request(item['image_url'])

    def file_path(self, request, response=None, info=None):
        return f'full/{request.url.split("/")[-1]}'

3. 使用Item Loader简化数据提取

from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, Join

class BookLoader(ItemLoader):
    default_output_processor = TakeFirst()
    description_out = Join()

def parse_book(self, response):
    loader = BookLoader(item=BookItem(), response=response)
    loader.add_css('title', 'h1::text')
    loader.add_css('price', 'p.price_color::text')
    loader.add_css('description', '#product_description + p::text')
    return loader.load_item()

性能优化建议

  1. 合理设置CONCURRENT_REQUESTS参数控制并发量
  2. 使用DOWNLOAD_DELAY避免请求过于频繁
  3. 启用HTTPCACHE_ENABLED缓存已爬取的页面
  4. 使用ROBOTSTXT_OBEY遵守网站爬虫协议
  5. 实现自定义重试机制处理异常情况

请始终注意:

  • 遵守网站的robots.txt规范
  • 合理控制爬取频率
  • 遵守网站的使用条款
  • 注意数据的合法使用

相关资源

关注我,每天推荐一款实用的Python爬虫工具