手记

Scrapy教程:初学者快速入门指南

概述

Scrapy教程介绍了如何安装和配置Scrapy框架,从创建第一个Scrapy项目到理解Scrapy的基本概念和数据提取技术。文章还涵盖了Scrapy的进阶功能,如中间件使用、并发设置和调试工具,帮助读者深入了解Scrapy的工作原理和使用方法。

Scrapy简介与安装

Scrapy是什么

Scrapy 是一个用于抓取网站数据、提取结构性信息并存储在本地文件系统或数据库中的强大、灵活的框架。它主要用于构建爬虫,即自动化的程序,这些程序可以访问互联网上的网页,提取网页上的信息,并按照一定的规则进行处理。

Scrapy 采用了一种异步的爬取模型,这意味着它可以同时处理多个请求,从而提高了爬取效率。它使用了 Twisted 异步框架来实现这种异步操作。

Scrapy 具有强大的数据提取功能。它可以通过 XPath、CSS 选择器等技术,从 HTML 或 XML 文档中提取所需的结构化数据。同时,Scrapy 也提供了丰富的中间件和扩展机制,使得开发者可以根据需求自定义爬虫的行为。

Scrapy的特点和优势

Scrapy 有许多特点和优势:

  • 异步执行:Scrapy 使用 Twisted 异步网络框架,可以在一个循环中处理多个请求。这意味着它可以快速地抓取大量数据,而不会因为网络延迟等问题影响性能。
  • 可扩展性:Scrapy 提供了高度可扩展的设计,支持不同的存储和提取策略。开发者可以轻松地添加新的中间件、扩展或管道,以适应不同的应用场景。
  • 强大且灵活:Scrapy 提供了许多强大的工具来构建和管理爬虫,如强大的 XPath 和 CSS 选择器支持,以及内置的请求处理和数据提取机制。
  • 易于维护和调试:Scrapy 提供了丰富的调试工具和日志记录能力,使得开发者可以轻松地调试和维护爬虫。
  • 社区支持和文档丰富:Scrapy 有一个活跃的社区和详细的文档,这使得开发者可以更容易地查找帮助和解决问题。

Scrapy的安装方法

Scrapy 可以通过 Python 的包管理工具 pip 安装。请确保您的计算机上已经安装了 Python 和 pip。

安装 Scrapy 请按照以下步骤操作:

pip install scrapy

安装完毕后,就可以开始使用 Scrapy 来创建爬虫了。

创建第一个Scrapy项目

项目结构介绍

Scrapy 项目的基本结构如下:

myproject/
    scrapy.cfg
    myproject/
        __init__.py
        items.py
        middlewares.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            example_spider.py
  • scrapy.cfg:这是 Scrapy 项目的配置文件,定义了项目的名称、启动命令等。
  • myproject:这是项目的主目录,包含所有 Scrapy 必要的组件和文件。
  • items.py:定义爬虫需要提取的数据结构。
  • middlewares.py:定义爬虫的中间件,用于处理请求和响应。
  • pipelines.py:定义数据处理管道,用于清洗和存储数据。
  • settings.py:Scrapy 项目的配置文件,包含了各种全局设置。
  • spiders:存放所有爬虫的目录。

items.py 示例

import scrapy

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

middlewares.py 示例

import scrapy

class MyProjectDownloaderMiddleware:
    def process_request(self, request, spider):
        # 自定义处理逻辑
        pass

pipelines.py 示例

import scrapy

class MyProjectPipeline:
    def process_item(self, item, spider):
        # 数据处理逻辑
        return item

settings.py 示例

BOT_NAME = 'myproject'
SPIDER_MODULES = ['myproject.spiders']
NEWSPIDER_MODULE = 'myproject.spiders'

创建新的Scrapy项目

要创建一个新的 Scrapy 项目,可以使用命令行工具。确保您已安装 Scrapy,然后在命令行中运行以下命令:

scrapy startproject myproject

这将创建一个名为 myproject 的新目录,其中包含 Scrapy 的基本结构。

example_spider.py 示例

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def parse(self, response):
        self.log(f'Visited {response.url}')

编写第一个Spider

接下来,我们编写一个简单的 Spider,从指定的网站抓取数据。

首先,在 myproject/spiders 目录下创建一个名为 example_spider.py 的文件。在该文件中,定义一个 Spider 类,如下所示:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def parse(self, response):
        self.log(f'Visited {response.url}')

这个简单的 Spider 类定义了以下几个属性和方法:

  • name:Spider 的名称,用于区分不同的 Spider。
  • start_urls:Spider 起始抓取的 URL 列表。Spider 将从这些 URL 开始抓取数据。
  • parse:这是 Spider 的主处理方法,用于解析响应并提取数据。默认情况下,parse 方法会处理所有从 start_urls 开始的响应。

接下来,运行这个 Spider:

scrapy crawl example

这将会启动爬虫,从 http://example.com 开始抓取数据,并打印访问过的 URL。

Scrapy的基本概念

Items和Fields

在 Scrapy 中,Items 用于定义要抓取的数据结构。每个 Item 都是一个 Python 类,定义了要抓取的数据字段。这些字段通过 Field 对象定义,这些字段将被数据提取和处理。

例如,假设我们要抓取一个网站上的书籍信息,我们可以定义一个 BookItem 类来表示这些信息:

import scrapy

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

在上面的例子中,我们定义了一个 BookItem 类,它包含 titleauthorpricepublish_date 四个字段。

Spiders和Start_urls

Spider 是 Scrapy 中负责抓取数据的主要组件。每个 Spider 都应该定义一个 name 属性,并且至少有一个 start_urls 属性,用于指定初始抓取的 URL 列表。

例如:

import scrapy

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

在这个例子中,BookSpider 是一个用于抓取书籍信息的 Spider。它的 name 属性被设置为 book_spider,并且 start_urls 列表包含一个 URL,该 URL 指向一个书籍列表页面。

Requests和Responses

RequestResponse 是 Scrapy 中用于处理网络请求和响应的两个核心对象。

  • RequestRequest 对象表示一个网络请求,它包含请求的 URL、HTTP 方法、回调函数等信息。Scrapy 会根据这些信息向指定的 URL 发出请求。
  • ResponseResponse 对象表示一个网络响应,它包含从请求 URL 返回的内容。每个 Response 对象都有一个 body 属性,该属性包含原始的 HTML 或 XML 内容。

例如,创建一个简单的请求:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        self.log(f'Visited {response.url}')

在上面的例子中,start_requests 方法生成了一个 Request 对象,并将其提交给 Scrapy。Request 对象的 callback 参数指定了当请求成功返回时调用的方法(即 parse 方法)。

Selectors和XPath

Selector 是 Scrapy 中用于提取 HTML 或 XML 文档中数据的工具。它提供了强大的 XPath 和 CSS 选择器支持,可以方便地提取结构化数据。

XPath 示例

XPath 是一种强大的查询语言,用于从 XML 和 HTML 文档中选择节点。例如,假设我们有一个简单的 HTML 文档,如下所示:

<html>
    <body>
        <div class="content">
            <h1>标题</h1>
            <p>段落1</p>
            <p>段落2</p>
        </div>
    </body>
</html>

我们可以使用 XPath 来提取其中的内容:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def parse(self, response):
        title = response.xpath('//h1/text()').get()
        paragraphs = response.xpath('//p/text()').getall()
        print(f'Title: {title}')
        print(f'Paragraphs: {paragraphs}')

在上面的例子中,使用 response.xpath('//h1/text()').get() 提取了 <h1> 标签内的文本内容。response.xpath('//p/text()').getall() 提取了所有 <p> 标签内的文本内容。

CSS 示例

CSS 选择器是一种简洁而强大的方法来选择 HTML 文档中的元素。例如,继续使用上面的 HTML 文档:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def parse(self, response):
        title = response.css('h1::text').get()
        paragraphs = response.css('p::text').getall()
        print(f'Title: {title}')
        print(f'Paragraphs: {paragraphs}')

在上面的例子中,使用 response.css('h1::text').get() 提取了 <h1> 标签内的文本内容。response.css('p::text').getall() 提取了所有 <p> 标签内的文本内容。

数据提取与处理

使用XPath提取数据

在 Scrapy 中,XPath 是一种强大的工具,用于从 HTML 或 XML 文档中提取数据。XPath 是一种查询语言,可以用来定位和选择文档中的节点。

例如,假设我们有一个简单的 HTML 文档,如下所示:

<html>
    <body>
        <div class="content">
            <h1>标题</h1>
            <p>段落1</p>
            <p>段落2</p>
        </div>
    </body>
</html>

我们可以使用 XPath 来提取其中的内容:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def parse(self, response):
        title = response.xpath('//h1/text()').get()
        paragraphs = response.xpath('//p/text()').getall()
        print(f'Title: {title}')
        print(f'Paragraphs: {paragraphs}')

在上面的例子中,response.xpath('//h1/text()').get() 提取了 <h1> 标签内的文本内容。response.xpath('//p/text()').getall() 提取了所有 <p> 标签内的文本内容。

使用CSS选择器提取数据

CSS 选择器是一种简洁而强大的方法来选择 HTML 文档中的元素。CSS 选择器具有简洁的语法,可以快速定位到指定的节点。

假设我们有以下 HTML 文档:

<html>
    <body>
        <div class="content">
            <h1>标题</h1>
            <p>段落1</p>
            <p>段落2</p>
        </div>
    </body>
</html>

我们可以使用 CSS 选择器来提取其中的内容:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def parse(self, response):
        title = response.css('h1::text').get()
        paragraphs = response.css('p::text').getall()
        print(f'Title: {title}')
        print(f'Paragraphs: {paragraphs}')

在上面的例子中,response.css('h1::text').get() 提取了 <h1> 标签内的文本内容。response.css('p::text').getall() 提取了所有 <p> 标签内的文本内容。

数据清洗与转换

在实际的应用中,从网页中抓取的数据往往需要进行清洗和转换,以满足特定的需求。Scrapy 提供了多种工具来实现数据的清洗和转换。

数据清洗

例如,假设我们抓取到的数据包含一些不需要的空格或换行符,可以通过 Python 的字符串方法进行清洗。

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = [
        'http://example.com',
    ]

    def parse(self, response):
        title = response.css('h1::text').get().strip()
        paragraphs = [p.strip() for p in response.css('p::text').getall()]
        print(f'Title: {title}')
        print(f'Paragraphs: {paragraphs}')

在上面的例子中,使用 strip() 方法去除了标题和段落中的多余空格。

数据转换

有时,我们可能需要将抓取的数据转换为特定的格式。例如,将抓取到的价格从字符串转换为浮点数。

import scrapy

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

    def parse(self, response):
        for book in response.css('article.product_pod'):
            title = book.css('h3 a::text').get()
            price = float(book.css('.price_color::text').re(r'\$(\d+\.\d+)')[0])
            yield {
                'title': title,
                'price': price,
            }

在上面的例子中,使用 re() 方法提取并转换了价格。

Scrapy进阶功能

中间件的使用

中间件是 Scrapy 中的一个重要概念,它允许开发者在请求和响应处理过程中插入自定义处理逻辑。中间件可以分为请求中间件和响应中间件,分别在请求发送前和响应接收后执行。

请求中间件

请求中间件在发送请求前执行。创建请求中间件需要继承 scrapy.core.downloader.middlewares.DownloaderMiddleware 类。

例如,一个简单的请求中间件,用于在请求中添加自定义的头信息:

import scrapy

class CustomHeadersMiddleware(scrapy.downloadermiddlewares.DownloaderMiddleware):
    def process_request(self, request, spider):
        request.headers['Custom-Header'] = 'Custom-Value'
        return request

settings.py 文件中启用该中间件:

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.CustomHeadersMiddleware': 600,
}

响应中间件

响应中间件在接收响应后执行。创建响应中间件需要继承 scrapy.core.downloader.middlewares.DownloaderMiddleware 类。

例如,一个简单的响应中间件,用于在响应中添加自定义的日志信息:

import scrapy

class CustomLogMiddleware(scrapy.downloadermiddlewares.DownloaderMiddleware):
    def process_response(self, request, response, spider):
        spider.logger.info(f'Received response for {request.url}')
        return response

settings.py 文件中启用该中间件:

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.CustomLogMiddleware': 700,
}

爬虫并发与延时设置

Scrapy 的一个强大特性是异步请求处理,这意味着它可以同时处理多个请求。为了控制爬虫的并发数量,可以在 settings.py 文件中设置 CONCURRENT_REQUESTS 参数:

CONCURRENT_REQUESTS = 10

这将允许同时处理最多 10 个请求。

此外,Scrapy 还允许为特定的 Spider 或域名设置不同的并发限制:

CONCURRENT_REQUESTS_PER_DOMAIN = 10
CONCURRENT_REQUESTS_PER_IP = 10

这些参数分别限制了每个域名和每个 IP 地址的最大并发请求数。

使用Scrapy Shell调试

Scrapy Shell 是一个强大的调试工具,可以帮助开发者在真实的 Spider 中进行调试。它提供了一个交互式的 Shell 环境,允许开发者直接与响应对象进行交互,以便更好地理解数据提取过程。

要启动 Scrapy Shell,可以在命令行中运行以下命令:

scrapy shell <url>

例如:

scrapy shell 'http://example.com'

进入 Scrapy Shell 后,可以使用 response 对象进行调试:

>>> response.css('h1::text').get()
'标题'
>>> response.xpath('//p/text()').getall()
['段落1', '段落2']

在上面的例子中,我们可以直接使用 XPath 和 CSS 选择器从响应中提取数据,并观察它们的结果。

Scrapy项目部署与维护

项目打包与发布

Scrapy 项目可以通过一些打包工具(如 setuptools)进行打包和发布,使得项目可以被部署到生产环境。以下是一个简单的打包和发布流程:

  1. 安装 setuptools:确保已经安装了 setuptools

    pip install setuptools
  2. 创建 setup.py 文件:在项目根目录下创建一个 setup.py 文件,定义项目的元数据和依赖项:

    from setuptools import setup, find_packages
    
    setup(
        name='myproject',
        version='0.1',
        packages=find_packages(),
        install_requires=[
            'Scrapy',
            # 其他依赖项
        ]
    )
  3. 打包:使用 setuptools 打包项目:

    python setup.py sdist bdist_wheel

    这将生成一个源代码包和一个二进制包。

  4. 发布到 PyPI:使用 twine 发布项目到 PyPI:

    pip install twine
    twine upload dist/*

setup.py 示例

from setuptools import setup, find_packages

setup(
    name='myproject',
    version='0.1',
    packages=find_packages(),
    install_requires=[
        'Scrapy',
        'Flask',  # 其他依赖项
    ]
)

Scrapy的日常维护与更新

Scrapy 项目的日常维护和更新包括以下几个方面:

  1. 版本管理:确保项目的版本号在每次更新时都正确更新。可以在 setup.py 文件中指定版本号。

  2. 依赖更新:定期检查项目的依赖项,并更新到最新版本。可以在 setup.py 文件的 install_requires 列表中更新依赖项。

  3. 代码审查:定期进行代码审查,确保代码的可读性和可维护性。可以使用代码审查工具如 flake8pylint

  4. 单元测试:编写单元测试以确保代码的正确性和稳定性。可以在 tests 目录下创建测试文件,并使用 pytestunittest 运行测试。

例如,创建一个简单的单元测试文件 test_spider.py

import unittest
from myproject.spiders.example_spider import ExampleSpider

class TestExampleSpider(unittest.TestCase):
    def test_example_spider(self):
        spider = ExampleSpider()
        response = spider.start_requests()[0]
        title = response.css('h1::text').get()
        self.assertIsNotNone(title)

运行单元测试:

pytest tests/

常见问题与解决方案

问题:Scrapy Spider 无法正确解析响应

解决方案:检查 Spider 中的 XPath 或 CSS 选择器是否正确。可以使用 Scrapy Shell 进行调试,验证选择器是否正确提取数据。

问题:Scrapy 无法连接到目标网站

解决方案:确保目标网站的 URL 正确,并且网站允许爬取。如果需要,可以设置代理或使用用户代理(User Agent)来增加访问成功率。

例如,设置代理:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,
    'myproject.middlewares.ProxyMiddleware': 100,
}

问题:Scrapy 的并发设置不合理

解决方案:调整 CONCURRENT_REQUESTSCONCURRENT_REQUESTS_PER_DOMAINCONCURRENT_REQUESTS_PER_IP 参数,找到适当的并发设置,以避免被目标网站封禁。

例如,限制每个域名的最大并发请求数:

CONCURRENT_REQUESTS_PER_DOMAIN = 5

问题:Scrapy 中间件不生效

解决方案:确保在 settings.py 文件中正确配置了中间件,并且中间件类实现了 process_requestprocess_response 方法。

例如,确保中间件类实现了 process_request 方法:

import scrapy

class CustomMiddleware(scrapy.downloadermiddlewares.DownloaderMiddleware):
    def process_request(self, request, spider):
        request.headers['Custom-Header'] = 'Custom-Value'
        return request
0人推荐
随时随地看视频
慕课网APP