继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Scrapy爬虫框架资料入门教程

翻阅古今
关注TA
已关注
手记 240
粉丝 9
获赞 36
概述

Scrapy爬虫框架资料介绍了Scrapy的强大功能和使用方法,包括其主要特点、安装步骤和项目创建过程。文章还详细讲解了如何编写和解析爬虫脚本,并提供了进阶技巧和实战案例,帮助读者全面掌握Scrapy的使用。

Scrapy入门介绍
Scrapy简介

Scrapy 是一个强大的 Python 爬虫框架,用于抓取网站内容并解析数据。它的设计目标是用于网站抓取与数据挖掘,支持快速爬取网站并从页面中提取结构化的数据。Scrapy 被广泛应用于各种场景,包括但不限于信息采集、数据监控、网络爬虫等。

Scrapy 的主要特点包括:

  • 异步爬取:Scrapy 使用 Twisted 异步网络库来处理网络请求,这意味着它可以同时发送多个请求,无需等待每个请求的响应。
  • 强大的数据提取能力:Scrapy 提供了多种方式来解析 HTML 和 XML 数据,包括 XPath、CSS 选择器等。
  • 灵活的数据管道:Scrapy 可以将爬取的数据传递给多个数据处理组件,例如保存到数据库、发送邮件等。
  • 中间件机制:中间件允许你自定义请求与响应处理逻辑,扩展 Scrapy 的功能。
  • 支持多种输出格式:可以将数据输出为 JSON、CSV 等多种格式。
安装Scrapy

要开始使用 Scrapy,首先需要在你的机器上安装 Scrapy。你可以使用 pip 工具来完成安装,pip 是 Python 的包管理工具。以下是安装 Scrapy 的步骤:

  1. 打开命令行工具(如 Windows 的命令提示符或 macOS/Linux 的终端)。
  2. 执行以下命令安装 Scrapy:
pip install Scrapy

安装完成后,你可以在命令行中输入 scrapy 来查看是否安装成功:

scrapy --version

如果成功安装,将显示 Scrapy 的版本信息。

第一个Scrapy项目

创建一个 Scrapy 项目,你可以使用 Scrapy 提供的命令行工具 scrapy startproject。以下步骤将引导你创建并运行一个简单的 Scrapy 项目。

  1. 创建一个新的 Scrapy 项目,这里我们将项目命名为 tutorial
scrapy startproject tutorial
  1. 切换到项目目录:
cd tutorial
  1. 在项目的 spiders 目录下创建一个新的爬虫文件 myspider.py,并编写一个简单的爬虫:
# tutorial/spiders/myspider.py
import scrapy

class MyspiderSpider(scrapy.Spider):
    name = 'myspider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/']

    def parse(self, response):
        print("URL: ", response.url)
  1. 运行爬虫:
scrapy crawl myspider

你将会看到输出类似如下内容:

2023-09-13 15:42:36 [scrapy.core.engine] INFO: Spider opened
2023-09-13 15:42:36 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.com/> (referer: None)
URL:  http://example.com/
2023-09-13 15:42:36 [scrapy.core.engine] INFO: Closing spider (reason: finished)

以上输出显示你的爬虫已经成功运行,并从 http://example.com/ 爬取了页面。

Scrapy架构解析
Scrapy的主要组件

Scrapy 架构由多个主要组件组成,这些组件协同工作以实现高效的数据抓取和处理。以下是 Scrapy 的主要组件及其功能:

  • 引擎(Engine):引擎是 Scrapy 架构的核心,负责处理整个爬取流程的控制。它负责与中间件、调度器、下载器交互,并控制爬虫的启动和停止。
  • 调度器(Scheduler):调度器负责管理请求队列,确保引擎按顺序发送请求。它从引擎接收请求,将请求加入队列,等待引擎请求时再返回。
  • 下载器(Downloader):下载器负责发送网络请求,并接收响应,然后将响应传回给引擎。下载器使用异步网络库 Twisted 来处理多个并发请求。
  • 中间件(Middleware):中间件允许自定义请求和响应的处理逻辑。中间件可以位于请求和响应的传递路径中,修改请求和响应,或执行其他操作。
  • 爬虫(Spider):爬虫是用户自定义的组件,负责抓取网页数据。爬虫定义了要抓取的 URL、要提取的数据和如何提取数据的逻辑。
  • 数据管道(Item Pipeline):数据管道负责处理爬虫提取的数据。数据通过管道组件传递,每个组件可以对数据进行处理、转换和存储。
  • 蜘蛛中间件(Spider Middleware):蜘蛛中间件专用于处理蜘蛛和引擎之间的请求和响应。它可以修改请求、响应、异常或中断爬取过程。
  • 下载器中间件(Downloader Middleware):下载器中间件则位于下载器和引擎之间,可以调整请求和响应的操作。

这些组件通过一个高度模块化的设计协同工作,使开发者能够方便地定制爬虫的行为和功能。

Scrapy的工作流程

Scrapy 的工作流程是按步骤执行的,保证了高效的数据抓取和处理。以下是 Scrapy 的一个典型工作流程:

  1. 引擎启动:引擎启动后,首先从爬虫中获取初始 URL,这些 URL 通常由 start_urls 列表定义。
  2. 调度请求:引擎将初始 URL 交给调度器,调度器将这些 URL 放入队列。
  3. 发送请求:引擎从调度器获取 URL,通过下载器发送网络请求。
  4. 接收响应:下载器收到服务器响应后,将响应发回给引擎。
  5. 解析响应:引擎将响应传递给相应的爬虫,爬虫调用 parse 方法解析数据。
  6. 提取数据:爬虫提取页面中的数据,生成 Item 对象并返回给引擎。
  7. 数据处理:引擎将提取的数据通过数据管道,管道中的组件可以进行数据清洗、验证等操作。
  8. 存储数据:最终,数据被存储到数据库或文件中。
  9. 生成更多请求:爬虫还可以生成新的请求,这些请求再次进入调度器队列,开始新一轮的抓取。

以上流程在 Scrapy 中不断迭代,直到所有需要抓取的 URL 都被处理完毕。这种设计使得 Scrapy 能够高效、灵活地处理大规模的数据抓取任务。

Scrapy项目的创建与配置
创建Scrapy项目

Scrapy 项目创建步骤如下:

  1. 打开命令行工具(如 Windows 的命令提示符或 macOS/Linux 的终端)。
  2. 执行命令 scrapy startproject 创建一个新的 Scrapy 项目,例如,创建一个名为 example 的项目:
scrapy startproject example
  1. 进入项目目录:
cd example
  1. 在项目目录中,你会看到以下文件和目录结构:
example/
├── example/
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders/
│       ├── __init__.py
│       └── myspider.py
├── scrapy.cfg
└── README.md
  • example/:主项目包,包含 Scrapy 项目的核心配置文件和模块。
  • spiders/:存放爬虫脚本的位置。
  • items.py:定义爬取数据的结构。
  • pipelines.py:定义数据处理流程。
  • settings.py:Scrapy 的配置文件。
  • middlewares.py:定义中间件逻辑。
  • scrapy.cfg:项目的配置文件。
  • README.md:项目说明文件。

这些文件将被用来构建和配置整个 Scrapy 项目。

项目配置详解

在 Scrapy 项目中,配置文件 settings.py 用于存放项目的全局配置。以下是一些常用的配置项和示例代码:

  1. 用户代理(User-Agent)
# 设置默认的 User-Agent
DEFAULT_REQUEST_HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
}
  1. 下载延迟(DOWNLOAD_DELAY)
# 设置每个请求之间的延迟时间(秒)
DOWNLOAD_DELAY = 1
  1. 重试中间件(RETRY_ENABLED)
# 启用或禁用重试中间件
RETRY_ENABLED = True
RETRY_TIMES = 5  # 设置重试次数
  1. 日志级别(LOG_LEVEL)
# 设置日志输出的级别
LOG_LEVEL = 'WARNING'
  1. 爬虫的并发请求(CONCURRENT_REQUESTS)
# 设置并发下载的请求数量
CONCURRENT_REQUESTS = 32
  1. 下载超时(DOWNLOAD_TIMEOUT)
# 设置下载超时时间(秒)
DOWNLOAD_TIMEOUT = 10
  1. 随机化并发数量(CONCURRENT_REQUESTS_PER_DOMAIN)
# 针对每个域名限制并发请求的数量
CONCURRENT_REQUESTS_PER_DOMAIN = 16
  1. 使用自定义中间件(DOWNLOADER_MIDDLEWARES)
# 启用自定义的 Downloader Middleware
DOWNLOADER_MIDDLEWARES = {
    'example.middlewares.MyCustomDownloaderMiddleware': 543,
}
  1. 启用或禁用 Spider 中间件(SPIDER_MIDDLEWARES)
# 启用或禁用 Spider Middleware
SPIDER_MIDDLEWARES = {
    'example.middlewares.MyCustomSpiderMiddleware': 543,
}
  1. 启用或禁用 Item Pipeline(ITEM_PIPELINES)
# 启用或禁用 Item Pipeline
ITEM_PIPELINES = {
    'example.pipelines.MyCustomPipeline': 300,
}

这些配置项可以显著影响 Scrapy 项目的行为和性能。根据实际需求调整这些配置参数,以优化爬虫的抓取效率和质量。

Scrapy爬虫编写基础
编写Spider类

在 Scrapy 中,爬虫(Spider)是用于从网站中抓取数据的核心组件。为了编写一个有效的爬虫,你需要了解几个关键概念,包括 start_urlsparse 方法和 Item 对象。以下是如何编写一个简单的 Scrapy 爬虫:

  1. 定义 Spider 类:Spider 类继承于 scrapy.Spider 类,必须定义 namestart_urlsparse 方法。
  2. start_urls:定义从哪个或哪些 URL 开始爬取。
  3. parse 方法:用于解析网页内容,提取所需的数据。

示例代码如下:

# example/spiders/myspider.py
import scrapy

class MyspiderSpider(scrapy.Spider):
    name = 'myspider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/']

    def parse(self, response):
        print("URL: ", response.url)

在上述示例中:

  • name 定义了爬虫的名称,用于在命令行中运行该爬虫。
  • allowed_domains 列出了允许爬取的域名。
  • start_urls 是爬虫初始请求的 URL 列表。
  • parse 方法是一个回调函数,用于处理响应内容,提取数据并生成新的请求(如果需要的话)。

递归抓取更多页面

在实际应用中,爬虫经常需要递归抓取更多页面。以下是一个示例,展示如何从首页开始,递归抓取更多页面:

class MyspiderSpider(scrapy.Spider):
    name = 'myspider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/']

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

        # 提取下一页链接
        next_page = response.css('a.next::attr(href)').get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)

在这个示例中,爬虫首先从 start_urls 列表中的 http://example.com/ 开始爬取,提取每个图书的标题和作者,并将它们作为 BookItem 对象返回。如果存在下一页链接,则继续递归抓取。

解析页面数据

解析页面数据是 Scrapy 爬虫的核心任务之一。Scrapy 提供了多种解析数据的方法,包括 XPath、CSS 选择器和正则表达式。这里我们将介绍如何使用 XPath 和 CSS 选择器来提取数据。

使用XPath解析数据

XPath 是一种强大的工具,用于在 XML 和 HTML 文档中导航和查找节点。在 Scrapy 中,你可以使用 XPath 来提取 HTML 中的数据。示例代码如下:

# example/spiders/xpath_spider.py
import scrapy

class XPathSpider(scrapy.Spider):
    name = 'xpath_spider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/']

    def parse(self, response):
        # 使用 XPath 提取标题
        title = response.xpath('//title/text()').get()
        print("Title: ", title)

在上述代码中,response.xpath('//title/text()').get() 使用 XPath 表达式 //title/text() 来定位 HTML 中 <title> 标签的内容,并返回第一个匹配项。

使用CSS选择器解析数据

CSS 选择器是另一种强大的工具,用于选择 HTML 中的节点。在 Scrapy 中,你可以使用 CSS 选择器来提取 HTML 中的数据。示例代码如下:

# example/spiders/css_spider.py
import scrapy

class CSSSpider(scrapy.Spider):
    name = 'css_spider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/']

    def parse(self, response):
        # 使用 CSS 选择器提取标题
        title = response.css('title::text').get()
        print("Title: ", title)

在上述代码中,response.css('title::text').get() 使用 CSS 选择器 title::text 来定位 HTML 中 <title> 标签的内容,并返回第一个匹配项。

提取所有匹配项

如果需要从多个匹配项中提取数据,可以使用 .extract().getall() 方法。示例代码如下:

# example/spiders/multiple_spider.py
import scrapy

class MultipleSpider(scrapy.Spider):
    name = 'multiple_spider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/']

    def parse(self, response):
        # 使用 CSS 选择器提取所有链接
        links = response.css('a::attr(href)').extract()
        for link in links:
            print("Link: ", link)

在上述代码中,response.css('a::attr(href)').extract() 使用 CSS 选择器 a::attr(href) 来提取所有 <a> 标签的 href 属性,并返回一个列表。

处理不同的响应类型

有时,你可能需要处理不同类型的数据,例如 JSON 或 XML。Scrapy 提供了 .json().xml() 方法来解析这些响应。示例代码如下:

# example/spiders/json_spider.py
import scrapy

class JSONSpider(scrapy.Spider):
    name = 'json_spider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/json']

    def parse(self, response):
        # 使用 .json() 解析 JSON 数据
        data = response.json()
        for item in data:
            print("Item: ", item)

在上述代码中,response.json() 用于解析 JSON 响应,并返回一个 Python 字典。

Scrapy进阶技巧
使用中间件

中间件(Middleware)是 Scrapy 的一个强大功能,允许你自定义请求和响应的处理逻辑。中间件可以位于请求和响应的传递路径中,修改请求和响应,或执行其他操作。以下是使用中间件的一些常见场景和示例代码:

自定义下载器中间件

下载器中间件(Downloader Middleware)位于下载器和引擎之间,可以用来处理请求和响应。以下是一个简单的下载器中间件示例,用于修改请求的 User-Agent:

# example/middlewares.py
import scrapy

class MyDownloaderMiddleware(scrapy.downloadermiddlewares.useragent.UserAgentMiddleware):
    def process_request(self, request, spider):
        request.headers['User-Agent'] = 'MyCustomUserAgent'
        return request

settings.py 中启用该中间件:

# example/settings.py
DOWNLOADER_MIDDLEWARES = {
    'example.middlewares.MyDownloaderMiddleware': 543,
}

处理重定向

Scrapy 提供了 RedirectMiddleware,可以处理自动重定向。你也可以自定义重定向中间件来处理重定向请求。以下是一个简单的重定向中间件示例:

# example/middlewares.py
import scrapy

class MyRedirectMiddleware(scrapy.downloadermiddlewares.redirect.RedirectMiddleware):
    def process_response(self, request, response, spider):
        if response.status in [301, 302]:
            redirected_url = response.headers['location'].decode()
            print("Redirected to: ", redirected_url)
            return scrapy.http.Request(redirected_url)
        return response

启用该中间件:

# example/settings.py
DOWNLOADER_MIDDLEWARES = {
    'example.middlewares.MyRedirectMiddleware': 543,
}

自定义蜘蛛中间件

蜘蛛中间件(Spider Middleware)位于蜘蛛和引擎之间,可以用来处理请求、响应和异常。以下是一个简单的蜘蛛中间件示例,用于记录请求和响应的 URL:

# example/middlewares.py
import scrapy

class MySpiderMiddleware(scrapy.spidermiddlewares.offsite.OffsiteMiddleware):
    def process_spider_output(self, response, result, spider):
        for item in result:
            print("Response URL: ", response.url)
            yield item

settings.py 中启用该中间件:

# example/settings.py
SPIDER_MIDDLEWARES = {
    'example.middlewares.MySpiderMiddleware': 543,
}

数据处理中间件

除了下载器和蜘蛛中间件,你还可以创建自定义的数据处理中间件来处理数据的传递。以下是一个简单的数据处理中间件示例,用于记录每个传递的数据项:

# example/middlewares.py
import scrapy

class MyItemPipeline(scrapy.pipeline.Pipeline):
    def process_item(self, item, spider):
        print("Processing item: ", item)
        return item

settings.py 中启用该中间件:

# example/settings.py
ITEM_PIPELINES = {
    'example.middlewares.MyItemPipeline': 300,
}

通过自定义中间件,你可以灵活地控制 Scrapy 的行为,使其更好地适应你的需求。

数据持久化

数据持久化是 Scrapy 项目中非常重要的一环,它允许你将爬取的数据保存到数据库或文件中。Scrapy 提供了数据管道(Item Pipeline)机制,使得数据处理和保存变得更加方便。以下是数据持久化的一些常见操作和示例代码:

定义Item对象

首先,定义一个 Item 类来表示你要抓取的数据结构。例如,我们抓取一个网站上的图书信息,包含书名和作者:

# example/items.py
import scrapy

class BookItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()

编写数据处理Pipeline

接下来,编写一个数据处理管道(Pipeline),将 Item 传递的数据进行处理并保存到文件或数据库中。以下是一个简单的数据处理管道示例,将 BookItem 保存到 CSV 文件中:

# example/pipelines.py
import csv
from scrapy.exceptions import DropItem

class BookPipeline:
    def __init__(self):
        self.file = open('books.csv', 'w', newline='', encoding='utf-8')
        self.writer = csv.writer(self.file)
        self.writer.writerow(['title', 'author'])

    def process_item(self, item, spider):
        if item['title'] and item['author']:
            self.writer.writerow([item['title'], item['author']])
            return item
        else:
            raise DropItem(f"Missing title or author in {item}")

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

settings.py 中启用该管道:

# example/settings.py
ITEM_PIPELINES = {
    'example.pipelines.BookPipeline': 300,
}

使用数据库保存数据

除了保存到文件,你还可以将数据保存到数据库,例如 MySQL 或 MongoDB。以下是一个示例,将数据保存到 MongoDB 数据库中:

安装依赖库

首先,安装 pymongo 依赖库:

pip install pymongo

创建数据库模型

创建一个数据库模型来表示 Book 表:

# example/models.py
import pymongo

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def save(self):
        client = pymongo.MongoClient('mongodb://localhost:27017/')
        db = client['scrapydb']
        collection = db['books']
        collection.insert_one({'title': self.title, 'author': self.author})
        client.close()

修改Pipeline处理数据

修改数据处理管道来调用数据库模型:

# example/pipelines.py
from example.models import Book

class BookPipeline:
    def process_item(self, item, spider):
        book = Book(item['title'], item['author'])
        book.save()
        return item

启用该管道:

# example/settings.py
ITEM_PIPELINES = {
    'example.pipelines.BookPipeline': 300,
}

数据清洗与验证

在数据处理管道中,你可以对数据进行清洗和验证,确保数据质量。例如,可以通过正则表达式检查数据格式:

# example/pipelines.py
import re

class BookPipeline:
    def process_item(self, item, spider):
        if not re.match(r'^\w+', item['title']):
            raise DropItem(f"Invalid title: {item['title']}")
        if not re.match(r'^\w+', item['author']):
            raise DropItem(f"Invalid author: {item['author']}")
        return item

通过数据处理管道,你可以灵活地控制数据的清洗、验证和持久化过程,确保爬取的数据质量。

实战案例分享
简单爬虫实例

爬取一个简单的网站

假设我们需要爬取一个简单的网站,例如一个展示图书列表的网站。首先,定义一个 BookItem 来表示图书信息:

# example/items.py
import scrapy

class BookItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()

接着,创建一个爬虫来抓取图书列表,并递归爬取更多页面:

# example/spiders/book_spider.py
import scrapy

class BookSpider(scrapy.Spider):
    name = 'book_spider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/books']

    def parse(self, response):
        # 提取图书列表
        for book in response.css('div.book'):
            item = BookItem()
            item['title'] = book.css('h2.title::text').get()
            item['author'] = book.css('div.author::text').get()
            yield item

        # 提取下一页链接
        next_page = response.css('a.next::attr(href)').get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)

在这个示例中,爬虫会从 start_urls 列表中的 http://example.com/books 开始爬取,提取每个图书的标题和作者,并将它们作为 BookItem 对象返回。如果存在下一页链接,则继续递归抓取。

运行爬虫

保存代码,通过命令行运行爬虫:

scrapy crawl book_spider

输出结果:

[scrapy.core.scraper] DEBUG: Scraped (item count: 1) from <GET http://example.com/books>
{'title': 'Book Title 1', 'author': 'Author 1'}
[scrapy.core.scraper] DEBUG: Scraped (item count: 2) from <GET http://example.com/books>
{'title': 'Book Title 2', 'author': 'Author 2'}

以上代码展示了如何抓取一个简单的网站并提取所需的数据。

复杂场景爬虫

处理分页和深度抓取

在实际应用中,网站可能会有分页、深度链接等复杂结构。我们需要编写爬虫来处理这些情况。以下是一个示例,处理一个图书网站的分页和深度链接。

假设我们需要爬取一个图书网站,该网站有多个分页,每页展示多个图书,并且每本书都有一个详情页面。首先,定义一个 BookItem

# example/items.py
import scrapy

class BookItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
    description = scrapy.Field()

然后,创建一个爬虫来处理分页和深度抓取:

# example/spiders/book_complex_spider.py
import scrapy

class BookComplexSpider(scrapy.Spider):
    name = 'book_complex_spider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/books']

    def parse(self, response):
        # 提取图书列表
        for book in response.css('div.book'):
            item = BookItem()
            item['title'] = book.css('h2.title::text').get()
            item['author'] = book.css('div.author::text').get()
            book_url = book.css('a::attr(href)').get()
            yield response.follow(book_url, callback=self.parse_book_page, meta={'item': item})

        # 提取下一页链接
        next_page = response.css('a.next::attr(href)').get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)

    def parse_book_page(self, response):
        item = response.meta['item']
        item['description'] = response.css('div.description::text').get()
        yield item

在这个示例中,爬虫会从 start_urls 列表中的 http://example.com/books 开始爬取,提取每个图书的标题和作者,并将它们作为 BookItem 对象传递到 parse_book_page 方法中。parse_book_page 方法从图书详情页面提取书的描述,并将完整信息返回。

运行复杂场景爬虫

保存代码,通过命令行运行爬虫:

scrapy crawl book_complex_spider

输出结果:

[scrapy.core.scraper] DEBUG: Scraped (item count: 1) from <GET http://example.com/books/1>
{'title': 'Book Title 1', 'author': 'Author 1', 'description': 'Description 1'}
[scrapy.core.scraper] DEBUG: Scraped (item count: 2) from <GET http://example.com/books/2>
{'title': 'Book Title 2', 'author': 'Author 2', 'description': 'Description 2'}

以上代码展示了如何处理分页和深度抓取的复杂网站结构,确保爬虫能够准确地抓取和提取所需的数据。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP