Scrapy爬虫框架资料介绍了Scrapy的强大功能和使用方法,包括其主要特点、安装步骤和项目创建过程。文章还详细讲解了如何编写和解析爬虫脚本,并提供了进阶技巧和实战案例,帮助读者全面掌握Scrapy的使用。
Scrapy入门介绍 Scrapy简介Scrapy 是一个强大的 Python 爬虫框架,用于抓取网站内容并解析数据。它的设计目标是用于网站抓取与数据挖掘,支持快速爬取网站并从页面中提取结构化的数据。Scrapy 被广泛应用于各种场景,包括但不限于信息采集、数据监控、网络爬虫等。
Scrapy 的主要特点包括:
- 异步爬取:Scrapy 使用 Twisted 异步网络库来处理网络请求,这意味着它可以同时发送多个请求,无需等待每个请求的响应。
- 强大的数据提取能力:Scrapy 提供了多种方式来解析 HTML 和 XML 数据,包括 XPath、CSS 选择器等。
- 灵活的数据管道:Scrapy 可以将爬取的数据传递给多个数据处理组件,例如保存到数据库、发送邮件等。
- 中间件机制:中间件允许你自定义请求与响应处理逻辑,扩展 Scrapy 的功能。
- 支持多种输出格式:可以将数据输出为 JSON、CSV 等多种格式。
要开始使用 Scrapy,首先需要在你的机器上安装 Scrapy。你可以使用 pip 工具来完成安装,pip 是 Python 的包管理工具。以下是安装 Scrapy 的步骤:
- 打开命令行工具(如 Windows 的命令提示符或 macOS/Linux 的终端)。
- 执行以下命令安装 Scrapy:
pip install Scrapy
安装完成后,你可以在命令行中输入 scrapy
来查看是否安装成功:
scrapy --version
如果成功安装,将显示 Scrapy 的版本信息。
第一个Scrapy项目创建一个 Scrapy 项目,你可以使用 Scrapy 提供的命令行工具 scrapy startproject
。以下步骤将引导你创建并运行一个简单的 Scrapy 项目。
- 创建一个新的 Scrapy 项目,这里我们将项目命名为
tutorial
:
scrapy startproject tutorial
- 切换到项目目录:
cd tutorial
- 在项目的
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)
- 运行爬虫:
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 的主要组件及其功能:
- 引擎(Engine):引擎是 Scrapy 架构的核心,负责处理整个爬取流程的控制。它负责与中间件、调度器、下载器交互,并控制爬虫的启动和停止。
- 调度器(Scheduler):调度器负责管理请求队列,确保引擎按顺序发送请求。它从引擎接收请求,将请求加入队列,等待引擎请求时再返回。
- 下载器(Downloader):下载器负责发送网络请求,并接收响应,然后将响应传回给引擎。下载器使用异步网络库 Twisted 来处理多个并发请求。
- 中间件(Middleware):中间件允许自定义请求和响应的处理逻辑。中间件可以位于请求和响应的传递路径中,修改请求和响应,或执行其他操作。
- 爬虫(Spider):爬虫是用户自定义的组件,负责抓取网页数据。爬虫定义了要抓取的 URL、要提取的数据和如何提取数据的逻辑。
- 数据管道(Item Pipeline):数据管道负责处理爬虫提取的数据。数据通过管道组件传递,每个组件可以对数据进行处理、转换和存储。
- 蜘蛛中间件(Spider Middleware):蜘蛛中间件专用于处理蜘蛛和引擎之间的请求和响应。它可以修改请求、响应、异常或中断爬取过程。
- 下载器中间件(Downloader Middleware):下载器中间件则位于下载器和引擎之间,可以调整请求和响应的操作。
这些组件通过一个高度模块化的设计协同工作,使开发者能够方便地定制爬虫的行为和功能。
Scrapy的工作流程Scrapy 的工作流程是按步骤执行的,保证了高效的数据抓取和处理。以下是 Scrapy 的一个典型工作流程:
- 引擎启动:引擎启动后,首先从爬虫中获取初始 URL,这些 URL 通常由
start_urls
列表定义。 - 调度请求:引擎将初始 URL 交给调度器,调度器将这些 URL 放入队列。
- 发送请求:引擎从调度器获取 URL,通过下载器发送网络请求。
- 接收响应:下载器收到服务器响应后,将响应发回给引擎。
- 解析响应:引擎将响应传递给相应的爬虫,爬虫调用
parse
方法解析数据。 - 提取数据:爬虫提取页面中的数据,生成
Item
对象并返回给引擎。 - 数据处理:引擎将提取的数据通过数据管道,管道中的组件可以进行数据清洗、验证等操作。
- 存储数据:最终,数据被存储到数据库或文件中。
- 生成更多请求:爬虫还可以生成新的请求,这些请求再次进入调度器队列,开始新一轮的抓取。
以上流程在 Scrapy 中不断迭代,直到所有需要抓取的 URL 都被处理完毕。这种设计使得 Scrapy 能够高效、灵活地处理大规模的数据抓取任务。
Scrapy项目的创建与配置 创建Scrapy项目Scrapy 项目创建步骤如下:
- 打开命令行工具(如 Windows 的命令提示符或 macOS/Linux 的终端)。
- 执行命令
scrapy startproject
创建一个新的 Scrapy 项目,例如,创建一个名为example
的项目:
scrapy startproject example
- 进入项目目录:
cd example
- 在项目目录中,你会看到以下文件和目录结构:
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
用于存放项目的全局配置。以下是一些常用的配置项和示例代码:
- 用户代理(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',
}
- 下载延迟(DOWNLOAD_DELAY):
# 设置每个请求之间的延迟时间(秒)
DOWNLOAD_DELAY = 1
- 重试中间件(RETRY_ENABLED):
# 启用或禁用重试中间件
RETRY_ENABLED = True
RETRY_TIMES = 5 # 设置重试次数
- 日志级别(LOG_LEVEL):
# 设置日志输出的级别
LOG_LEVEL = 'WARNING'
- 爬虫的并发请求(CONCURRENT_REQUESTS):
# 设置并发下载的请求数量
CONCURRENT_REQUESTS = 32
- 下载超时(DOWNLOAD_TIMEOUT):
# 设置下载超时时间(秒)
DOWNLOAD_TIMEOUT = 10
- 随机化并发数量(CONCURRENT_REQUESTS_PER_DOMAIN):
# 针对每个域名限制并发请求的数量
CONCURRENT_REQUESTS_PER_DOMAIN = 16
- 使用自定义中间件(DOWNLOADER_MIDDLEWARES):
# 启用自定义的 Downloader Middleware
DOWNLOADER_MIDDLEWARES = {
'example.middlewares.MyCustomDownloaderMiddleware': 543,
}
- 启用或禁用 Spider 中间件(SPIDER_MIDDLEWARES):
# 启用或禁用 Spider Middleware
SPIDER_MIDDLEWARES = {
'example.middlewares.MyCustomSpiderMiddleware': 543,
}
- 启用或禁用 Item Pipeline(ITEM_PIPELINES):
# 启用或禁用 Item Pipeline
ITEM_PIPELINES = {
'example.pipelines.MyCustomPipeline': 300,
}
这些配置项可以显著影响 Scrapy 项目的行为和性能。根据实际需求调整这些配置参数,以优化爬虫的抓取效率和质量。
Scrapy爬虫编写基础 编写Spider类在 Scrapy 中,爬虫(Spider)是用于从网站中抓取数据的核心组件。为了编写一个有效的爬虫,你需要了解几个关键概念,包括 start_urls
、parse
方法和 Item
对象。以下是如何编写一个简单的 Scrapy 爬虫:
- 定义 Spider 类:Spider 类继承于
scrapy.Spider
类,必须定义name
、start_urls
和parse
方法。 - start_urls:定义从哪个或哪些 URL 开始爬取。
- 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 字典。
中间件(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'}
以上代码展示了如何处理分页和深度抓取的复杂网站结构,确保爬虫能够准确地抓取和提取所需的数据。
共同学习,写下你的评论
评论加载中...
作者其他优质文章