Python3入门指南Python语言的特点和实际应用Python3环境搭建配置VSCode进行Python开发Python基础语法Python变量与数据类型Python数据类型转换Python解释器使用Python注释使用Python运算符Python数字类型Python字符串操作Python列表操作Python元组使用Python字典使用Python集合使用Python条件控制详解Python循环语句详解Python编程入门实践Python推导式详解Python迭代器和生成器Python with语句详解Python函数详解Python lambda(匿名函数)Python装饰器Python数据结构Python模块和包使用Python中__name__和__main__的用法Python输入输出:从基础到文件操作Python文件操作Python OS模块使用Python错误和异常处理Python面向对象编程Python命名空间和作用域Python虚拟环境:venv详细教程Python类型注解Python标准库常用模块Python正则表达式Python CGI编程Python MySQL(mysql-connector驱动)Python MySQL(PyMySQL驱动)Python网络编程Python发送邮件Python多线程编程Python XML解析Python JSON解析Python日期和时间处理Python操作MongoDBPython urllib库使用Python uWSGI 安装与配置Python pip包管理工具Python operator模块Python math模块Python requests模块HTTP请求Python random模块Python OpenAI库Python AI绘画制作Python statistics模块Python hashlib模块:哈希加密Python量化交易Python pyecharts数据可视化Python Selenium网页自动化Python BeautifulSoup网页数据提取Python Scrapy爬虫框架Python Markdown转HTMLPython sys模块Python Pickle模块:数据存储Python subprocess模块Python queue队列模块Python StringIO内存文件操作Python logging日志记录Python datetime日期时间处理Python re正则表达式Python csv表格数据处理Python threading 多线程编程Python asyncio 异步编程Python PyQt 图形界面开发Python 应用方向和常用库框架

Python Scrapy爬虫框架

Scrapy是一个专业的Python爬虫框架,专门用于高效抓取网页数据。相比简单的requests库,Scrapy提供了完整的爬虫解决方案,适合处理大规模数据采集任务。

Scrapy 官网:https://scrapy.org/


Scrapy框架特点

Scrapy具有很多强大功能:

  • 自动处理请求和响应

  • 支持数据清洗和存储

  • 可以控制爬取速度

  • 支持分布式爬取

  • 有完善的错误处理机制


安装Scrapy

使用pip安装Scrapy:

pip install scrapy

安装完成后,可以检查版本:

scrapy version


创建第一个Scrapy项目

创建项目结构

使用命令行创建Scrapy项目:

scrapy startproject my_spider_project

这个命令会创建一个项目文件夹,包含以下结构:

my_spider_project/
    scrapy.cfg
    my_spider_project/
        __init__.py
        items.py
        middlewares.py
        pipelines.py
        settings.py
        spiders/
            __init__.py

创建爬虫

进入项目目录,创建第一个爬虫:

cd my_spider_project
scrapy genspider example_spider example.com

这会生成一个爬虫文件 spiders/example_spider.py。


编写爬虫代码

基本爬虫结构

打开生成的爬虫文件,修改内容:

import scrapy

class ExampleSpiderSpider(scrapy.Spider):
    name = "example_spider"
    allowed_domains = ["example.com"]
    start_urls = ["https://example.com"]

    def parse(self, response):
        # 提取页面标题
        title = response.css('title::text').get()
        
        # 返回提取的数据
        yield {
            'title': title,
            'url': response.url
        }

代码说明:

  • name:爬虫的唯一名称

  • allowed_domains:允许爬取的域名

  • start_urls:起始网址列表

  • parse:处理响应和提取数据的方法

运行爬虫

在项目目录下运行:

scrapy crawl example_spider


实际爬虫示例

爬取图书信息

创建一个爬取图书信息的爬虫:

import scrapy

class BookSpider(scrapy.Spider):
    name = "book_spider"
    start_urls = [
        'https://books.example.com/catalogue/page-1.html',
    ]

    def parse(self, response):
        # 提取每本图书的信息
        books = response.css('article.product_pod')
        
        for book in books:
            yield {
                'title': book.css('h3 a::attr(title)').get(),
                'price': book.css('p.price_color::text').get(),
                'rating': book.css('p.star-rating::attr(class)').get().split()[-1],
                'link': response.urljoin(book.css('h3 a::attr(href)').get())
            }
        
        # 处理分页
        next_page = response.css('li.next a::attr(href)').get()
        if next_page:
            yield response.follow(next_page, self.parse)

配置爬虫设置

修改 settings.py 文件来配置爬虫:

# 设置用户代理,模拟浏览器
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'

# 遵守robots.txt规则
ROBOTSTXT_OBEY = True

# 下载延迟,避免请求过快
DOWNLOAD_DELAY = 2

# 并发请求数
CONCURRENT_REQUESTS = 16

# 启用自动限速
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 2
AUTOTHROTTLE_MAX_DELAY = 5


定义数据结构

使用Item类

在 items.py 中定义数据结构:

import scrapy

class BookItem(scrapy.Item):
    # 定义字段
    title = scrapy.Field()
    price = scrapy.Field()
    rating = scrapy.Field()
    description = scrapy.Field()
    link = scrapy.Field()
    crawled_time = scrapy.Field()

在爬虫中使用Item:

from my_spider_project.items import BookItem

class BookSpider(scrapy.Spider):
    name = "book_spider"
    
    def parse(self, response):
        book = BookItem()
        book['title'] = response.css('h1::text').get()
        book['price'] = response.css('.price_color::text').get()
        book['crawled_time'] = datetime.now().isoformat()
        
        yield book


数据处理管道

创建数据管道

在 pipelines.py 中处理爬取的数据:

import json
import csv

class JsonWriterPipeline:
    def open_spider(self, spider):
        self.file = open('books.json', 'w', encoding='utf-8')
        self.file.write('[\n')
        self.first_item = True

    def close_spider(self, spider):
        self.file.write('\n]')
        self.file.close()

    def process_item(self, item, spider):
        # 转换数据为JSON格式
        line = json.dumps(dict(item), ensure_ascii=False)
        
        if not self.first_item:
            self.file.write(',\n')
        self.file.write('    ' + line)
        self.first_item = False
        
        return item

class PriceFilterPipeline:
    def process_item(self, item, spider):
        # 过滤价格过高的图书
        price = item.get('price')
        if price:
            # 移除货币符号并转换为浮点数
            price_value = float(price.replace('£', '').replace('$', ''))
            if price_value > 50:  # 如果价格超过50,丢弃该条目
                raise DropItem(f"价格过高: {price}")
        return item

启用管道

在 settings.py 中启用管道:

ITEM_PIPELINES = {
    'my_spider_project.pipelines.PriceFilterPipeline': 100,
    'my_spider_project.pipelines.JsonWriterPipeline': 200,
}

数字表示优先级,越小越先执行。


中间件使用

自定义中间件

在 middlewares.py 中添加自定义功能:

import random
from scrapy import signals

class RandomUserAgentMiddleware:
    def __init__(self):
        self.user_agents = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
        ]

    def process_request(self, request, spider):
        # 随机选择用户代理
        request.headers['User-Agent'] = random.choice(self.user_agents)

class ProxyMiddleware:
    def process_request(self, request, spider):
        # 设置代理
        request.meta['proxy'] = 'http://your-proxy-server:port'

启用中间件:

DOWNLOADER_MIDDLEWARES = {
    'my_spider_project.middlewares.RandomUserAgentMiddleware': 400,
    'my_spider_project.middlewares.ProxyMiddleware': 500,
}


数据提取技巧

CSS选择器

def parse(self, response):
    # 提取文本
    title = response.css('h1::text').get()
    
    # 提取属性
    image_url = response.css('img.product_image::attr(src)').get()
    
    # 提取多个元素
    categories = response.css('.breadcrumb li a::text').getall()
    
    # 使用正则表达式过滤
    price = response.css('.price_color::text').re_first(r'[\d.]+')
    
    return {
        'title': title,
        'image': response.urljoin(image_url),
        'categories': categories,
        'price': price
    }

XPath选择器

def parse(self, response):
    # 使用XPath提取数据
    title = response.xpath('//h1/text()').get()
    
    # 提取包含特定文本的元素
    in_stock = response.xpath('//p[contains(@class, "instock")]/text()').get()
    
    # 复杂的XPath查询
    rating = response.xpath('//p[contains(@class, "star-rating")]/@class').re_first(r'star-rating (\w+)')
    
    return {
        'title': title,
        'in_stock': '有货' if '有货' in in_stock else '缺货',
        'rating': rating
    }


处理分页和链接跟踪

自动分页

class PaginatedSpider(scrapy.Spider):
    name = "paginated_spider"
    
    def start_requests(self):
        # 自定义起始请求
        urls = ['https://example.com/catalogue/page-1.html']
        for url in urls:
            yield scrapy.Request(url, callback=self.parse)
    
    def parse(self, response):
        # 提取当前页数据
        for product in response.css('.product_pod'):
            yield {
                'name': product.css('h3 a::attr(title)').get(),
                'price': product.css('.price_color::text').get()
            }
        
        # 自动跟踪下一页
        next_page = response.css('li.next a::attr(href)').get()
        if next_page:
            yield response.follow(next_page, self.parse)

深度爬取

class DeepCrawlSpider(scrapy.Spider):
    name = "deep_crawl"
    
    def parse(self, response):
        # 提取详情页链接
        detail_links = response.css('.product_pod h3 a::attr(href)').getall()
        
        for link in detail_links:
            yield response.follow(link, self.parse_detail)
        
        # 继续分页
        next_page = response.css('.next a::attr(href)').get()
        if next_page:
            yield response.follow(next_page, self.parse)
    
    def parse_detail(self, response):
        # 解析详情页
        yield {
            'title': response.css('h1::text').get(),
            'description': response.css('#product_description + p::text').get(),
            'price': response.css('.price_color::text').get(),
            'url': response.url
        }


数据导出

多种格式导出

运行爬虫时可以直接导出数据:

# 导出为JSON
scrapy crawl book_spider -o books.json

# 导出为CSV
scrapy crawl book_spider -o books.csv

# 导出为XML
scrapy crawl book_spider -o books.xml

# 分块导出
scrapy crawl book_spider -o books.jl  # JSON Lines格式

自定义导出

class CustomExportPipeline:
    def open_spider(self, spider):
        self.csv_file = open('custom_export.csv', 'w', newline='', encoding='utf-8')
        self.writer = csv.writer(self.csv_file)
        self.writer.writerow(['标题', '价格', '评分', '爬取时间'])
    
    def close_spider(self, spider):
        self.csv_file.close()
    
    def process_item(self, item, spider):
        self.writer.writerow([
            item.get('title', ''),
            item.get('price', ''),
            item.get('rating', ''),
            item.get('crawled_time', '')
        ])
        return item


错误处理和重试

自动重试机制

class RobustSpider(scrapy.Spider):
    name = "robust_spider"
    
    def start_requests(self):
        # 设置自定义请求参数
        for url in self.start_urls:
            yield scrapy.Request(
                url,
                callback=self.parse,
                errback=self.errback,
                meta={
                    'max_retry_times': 3,
                    'retry_delay': 1000  # 1秒
                }
            )
    
    def parse(self, response):
        # 正常解析逻辑
        pass
    
    def errback(self, failure):
        # 错误处理
        self.logger.error(f"请求失败: {failure.value}")
        
        # 可以在这里实现重试逻辑
        if failure.check(HttpError):
            response = failure.value.response
            self.logger.error(f'HTTP错误: {response.status}')


实用命令行工具

Scrapy Shell调试

# 启动交互式shell
scrapy shell 'https://example.com'

# 在shell中测试选择器
>>> response.css('title::text').get()
>>> view(response)  # 在浏览器中查看响应

其他有用命令

# 查看爬虫列表
scrapy list

# 检查爬虫代码
scrapy check book_spider

# 下载网页内容查看
scrapy fetch --nolog 'https://example.com'

# 在浏览器中查看Scrapy下载的页面
scrapy view 'https://example.com'


最佳实践建议

  1. 遵守robots.txt:尊重网站的爬虫规则

  2. 设置合理延迟:避免对网站造成压力

  3. 使用用户代理:模拟真实浏览器行为

  4. 处理异常:添加完善的错误处理

  5. 限制爬取范围:只爬取需要的数据

  6. 保存爬取状态:支持断点续爬

  7. 监控爬取进度:记录日志和统计信息


项目结构示例

一个完整的Scrapy项目通常包含:

my_scrapy_project/
    scrapy.cfg
    my_scrapy_project/
        __init__.py
        items.py          # 数据模型
        pipelines.py      # 数据处理
        settings.py       # 配置
        middlewares.py    # 中间件
        spiders/
            __init__.py
            books.py      # 图书爬虫
            news.py       # 新闻爬虫
        utils/
            __init__.py
            helpers.py    # 辅助函数


常用方法

1. 爬虫方法

方法名作用描述示例
start_requests()生成初始请求,可以自定义请求头、请求方法等。yield scrapy.Request(url, callback=self.parse)
parse(response)处理响应并提取数据,是爬虫的核心方法。yield {'title': response.css('h1::text').get()}
follow(url, callback)自动处理相对 URL 并生成新的请求,用于分页或链接跳转。yield response.follow(next_page, callback=self.parse)
closed(reason)爬虫关闭时调用,用于清理资源或记录日志。def closed(self, reason): print('Spider closed:', reason)
log(message)记录日志信息。self.log('This is a log message')

2. 数据提取方法

方法名作用描述示例
response.css(selector)使用 CSS 选择器提取数据。title = response.css('h1::text').get()
response.xpath(selector)使用 XPath 选择器提取数据。title = response.xpath('//h1/text()').get()
get()从 SelectorList 中提取第一个匹配的结果(字符串)。title = response.css('h1::text').get()
getall()从 SelectorList 中提取所有匹配的结果(列表)。titles = response.css('h1::text').getall()
attrib提取当前节点的属性。link = response.css('a::attr(href)').get()

3. 请求与响应方法

方法名作用描述示例
scrapy.Request(url, callback, method, headers, meta)创建一个新的请求。yield scrapy.Request(url, callback=self.parse, headers=headers)
response.url获取当前响应的 URL。current_url = response.url
response.status获取响应的状态码。if response.status == 200: print('Success')
response.meta获取请求中传递的额外数据。value = response.meta.get('key')
response.headers获取响应的头信息。content_type = response.headers.get('Content-Type')

4. 中间件与管道方法

方法名作用描述示例
process_request(request, spider)在请求发送前处理请求(下载器中间件)。request.headers['User-Agent'] = 'Mozilla/5.0'
process_response(request, response, spider)在响应返回后处理响应(下载器中间件)。if response.status == 403: return request.replace(dont_filter=True)
process_item(item, spider)处理提取的数据(管道)。if item['price'] < 0: raise DropItem('Invalid price')
open_spider(spider)爬虫启动时调用(管道)。def open_spider(self, spider): self.file = open('items.json', 'w')
close_spider(spider)爬虫关闭时调用(管道)。def close_spider(self, spider): self.file.close()

5. 工具与扩展方法

方法名作用描述示例
scrapy shell启动交互式 Shell,用于调试和测试选择器。scrapy shell 'http://example.com'
scrapy crawl <spider_name>运行指定的爬虫。scrapy crawl myspider -o output.json
scrapy check检查爬虫代码的正确性。scrapy check
scrapy fetch下载指定 URL 的内容。scrapy fetch 'http://example.com'
scrapy view在浏览器中查看 Scrapy 下载的页面。scrapy view 'http://example.com'

6. 常用设置(settings.py)

设置项作用描述示例
USER_AGENT设置请求头中的 User-Agent。USER_AGENT = 'Mozilla/5.0'
ROBOTSTXT_OBEY是否遵守 robots.txt 规则。ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY设置下载延迟,避免过快请求。DOWNLOAD_DELAY = 2
CONCURRENT_REQUESTS设置并发请求数。CONCURRENT_REQUESTS = 16
ITEM_PIPELINES启用管道。ITEM_PIPELINES = {'myproject.pipelines.MyPipeline': 300}
AUTOTHROTTLE_ENABLED启用自动限速扩展。AUTOTHROTTLE_ENABLED = True

7. 其他常用方法

方法名作用描述示例
response.follow_all(links, callback)批量处理链接并生成请求。yield from response.follow_all(links, callback=self.parse)
response.json()将响应内容解析为 JSON 格式。data = response.json()
response.text获取响应的文本内容。html = response.text
response.selector获取响应内容的 Selector 对象。title = response.selector.css('h1::text').get()

以上表格列出了 Scrapy 中常用的方法及其作用。这些方法涵盖了爬虫开发的各个方面,包括请求生成、数据提取、中间件处理、管道操作等。通过掌握这些方法,你可以高效地编写和管理 Scrapy 爬虫。


总结

Scrapy是一个功能完整的爬虫框架,适合处理复杂的网页抓取任务。主要特点包括:

  • 结构化的项目组织

  • 强大的数据提取能力

  • 灵活的数据处理管道

  • 可扩展的中间件系统

  • 完善的配置管理

对于简单的爬虫任务,可以使用requests+BeautifulSoup组合。但对于大规模、复杂的爬虫项目,Scrapy是更好的选择。

记住在使用爬虫时要遵守相关法律法规和网站的使用条款。

本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/course/36_2135

目录选择