4.1 Scrapy 项目实战流程 4.1 Scrapy 项目实战流程详解 项目初始化 首先,我们需要创建一个 Scrapy 项目。 这可以通过命令行工具 完成: 这会在当前目录下创建一个名为 的文件夹,其中包含以下结构: mermaid graph TD: 定义 Item 文件用于定义要抓取的数据结构,类似于 ORM 中的模型。 例如,我们要抓取图书信息,可以定义一个 : 每个字段都是 的实例,这允许 Scrapy 对数据进行处理和验证。 创建 Spider Spider 是 Scrapy 的核心组件,负责定义如何抓取网页并提取数据。 在 目录下创建一个 Spider 文件,例如 : : Spider 的唯一名称,用于在命令行中启动 Spider。
首先,我们需要创建一个 Scrapy 项目。 这可以通过命令行工具 scrapy 完成:
scrapy startproject my_spider_project
这会在当前目录下创建一个名为 my_spider_project 的文件夹,其中包含以下结构:
my_spider_project/ scrapy.cfg # 部署配置文件 my_spider_project/ # 项目 Python 模块 __init__.py items.py # 定义要抓取的数据结构 middlewares.py # 定义 Spider 中间件 pipelines.py # 定义 Item Pipeline settings.py # 项目设置 spiders/ # 存放 Spider 的目录 __init__.py
mermaid graph TD:
items.py 文件用于定义要抓取的数据结构,类似于 ORM 中的模型。 例如,我们要抓取图书信息,可以定义一个 BookItem:
# my_spider_project/items.py import scrapy class BookItem(scrapy.Item): title = scrapy.Field() author = scrapy.Field() price = scrapy.Field() # 可以添加更多字段
每个字段都是 scrapy.Field() 的实例,这允许 Scrapy 对数据进行处理和验证。
Spider 是 Scrapy 的核心组件,负责定义如何抓取网页并提取数据。 在 spiders 目录下创建一个 Spider 文件,例如 book_spider.py:
# my_spider_project/spiders/book_spider.py import scrapy from my_spider_project.items import BookItem class BookSpider(scrapy.Spider): name = "books" # Spider 的名称,用于区分不同的 Spider allowed_domains = ["example.com"] # 允许抓取的域名 start_urls = ["http://example.com/books"] # 起始 URL def parse(self, response): # 使用 CSS 选择器或 XPath 提取数据 for book in response.css(".book"): item = BookItem() item['title'] = book.css(".title::text").get() item['author'] = book.css(".author::text").get() item['price'] = book.css(".price::text").get() yield item # 使用 yield 返回 Item,Scrapy 会自动处理
name: Spider 的唯一名称,用于在命令行中启动 Spider。
allowed_domains: 允许 Spider 抓取的域名列表,防止爬虫爬到其他网站。
start_urls: Spider 启动时要抓取的 URL 列表。
parse: 回调函数,用于处理每个 URL 的响应。 它接收 response 对象,可以使用 CSS 选择器或 XPath 提取数据,并将数据封装到 Item 中。 yield 关键字用于返回 Item,Scrapy 会自动将其传递到 Item Pipeline。
mermaid graph TD:
在 parse 方法中,我们使用 CSS 选择器或 XPath 从网页中提取数据。 Scrapy 提供了方便的 API 来进行选择:
response.css(selector): 使用 CSS 选择器选择元素。
response.xpath(query): 使用 XPath 查询选择元素。
.get(): 获取选择器的第一个结果。
.getall(): 获取选择器的所有结果,返回列表。
例如,以下代码使用 CSS 选择器提取标题:
title = response.css(".title::text").get()
以下代码使用 XPath 提取作者:
author = response.xpath("//div[@class='author']/text()").get()
Item Pipeline 负责处理 Spider 提取的 Item。 它可以用于数据清洗、验证、存储等。 在 pipelines.py 文件中定义 Item Pipeline:
# my_spider_project/pipelines.py import json class BookPipeline: def __init__(self): self.file = open("books.json", "w") def process_item(self, item, spider): line = json.dumps(dict(item)) + "\n" self.file.write(line) return item def close_spider(self, spider): self.file.close()
process_item(item, spider): 处理每个 Item 的方法。 必须返回 Item 或抛出 DropItem 异常。
open_spider(spider): 在 Spider 启动时调用。
close_spider(spider): 在 Spider 关闭时调用。
要启用 Item Pipeline,需要在 settings.py 中配置:
# my_spider_project/settings.py ITEM_PIPELINES = { 'my_spider_project.pipelines.BookPipeline': 300, }
数字 300 表示 Pipeline 的优先级,数字越小优先级越高。
mermaid graph TD:
settings.py 文件用于配置 Scrapy 项目的各种设置,例如:
BOT_NAME: 爬虫的名称。
ROBOTSTXT_OBEY: 是否遵守 robots.txt 协议。
DEFAULT_REQUEST_HEADERS: 默认的请求头。
DOWNLOAD_DELAY: 下载延迟,防止被网站封禁。
ITEM_PIPELINES: 启用的 Item Pipeline。
FEED_FORMAT: 导出数据的格式。
FEED_URI: 导出数据的 URI。
例如,以下代码配置导出数据为 JSON 格式:
# my_spider_project/settings.py FEED_FORMAT = "json" FEED_URI = "books.json"
使用以下命令运行 Spider:
scrapy crawl books
其中 books 是 Spider 的名称。 Scrapy 将会启动 Spider,抓取数据,并将其传递到 Item Pipeline 进行处理。
Scrapy 的中间件提供了在请求和响应处理过程中插入自定义逻辑的机会。 有两种类型的中间件:
Spider 中间件: 在 Spider 处理响应之前和之后执行。 可以用于修改请求、处理响应、处理异常等。
Downloader 中间件: 在 Scrapy 下载器下载响应之前和之后执行。 可以用于添加请求头、设置代理、处理重试等。
在 middlewares.py 文件中定义中间件。 例如,以下代码定义一个简单的 Downloader 中间件,用于添加 User-Agent 请求头:
# my_spider_project/middlewares.py class CustomUserAgentMiddleware: def process_request(self, request, spider): request.headers['User-Agent'] = 'My Custom User Agent' def process_response(self, request, response, spider): return response def process_exception(self, request, exception, spider): pass
要启用中间件,需要在 settings.py 中配置:
# my_spider_project/settings.py DOWNLOADER_MIDDLEWARES = { 'my_spider_project.middlewares.CustomUserAgentMiddleware': 543, }
数字 543 表示中间件的优先级,数字越小优先级越高。
Scrapy 项目可以部署到各种平台,例如:
Scrapinghub: Scrapinghub 是一个专门为 Scrapy 提供的云平台,提供爬虫部署、调度、监控等功能。
Docker: 使用 Docker 可以将 Scrapy 项目打包成一个容器,方便部署到任何支持 Docker 的平台。
服务器: 可以将 Scrapy 项目部署到自己的服务器上,使用 Supervisor 或 systemd 等工具进行管理。
这是一个更完整的示例,演示如何抓取 Quotes to Scrape 网站上的名言:
# my_spider_project/items.py import scrapy class QuoteItem(scrapy.Item): text = scrapy.Field() author = scrapy.Field() tags = scrapy.Field() # my_spider_project/spiders/quotes_spider.py import scrapy from my_spider_project.items import QuoteItem 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'): item = QuoteItem() item['text'] = quote.css('span.text::text').get() item['author'] = quote.css('small.author::text').get() item['tags'] = quote.css('div.tags a.tag::text').getall() yield item next_page = response.css('li.next a::attr(href)').get() if next_page is not None: yield response.follow(next_page, self.parse) # my_spider_project/pipelines.py import json class JsonWriterPipeline: def __init__(self): self.file = open('quotes.json', 'w') def process_item(self, item, spider): line = json.dumps(dict(item)) + "\n" self.file.write(line) return item def close_spider(self, spider): self.file.close() # my_spider_project/settings.py ITEM_PIPELINES = { 'my_spider_project.pipelines.JsonWriterPipeline': 300, }
这个例子展示了如何:
定义 Item (QuoteItem).
创建一个 Spider (QuotesSpider),抓取 Quotes to Scrape 网站上的名言。
使用 CSS 选择器提取名言、作者和标签。
使用 response.follow() 自动抓取下一页。
创建一个 Item Pipeline (JsonWriterPipeline),将数据保存到 JSON 文件。