Scrapy爬虫框架资料介绍了Scrapy的强大功能和使用方法,包括其主要特点、安装步骤和项目创建过程。文章还详细讲解了如何编写和解析爬虫脚本,并提供了进阶技巧和实战案例,帮助读者全面掌握Scrapy的使用。
Scrapy 是一个强大的 Python 爬虫框架,用于抓取网站内容并解析数据。它的设计目标是用于网站抓取与数据挖掘,支持快速爬取网站并从页面中提取结构化的数据。Scrapy 被广泛应用于各种场景,包括但不限于信息采集、数据监控、网络爬虫等。
Scrapy 的主要特点包括:
要开始使用 Scrapy,首先需要在你的机器上安装 Scrapy。你可以使用 pip 工具来完成安装,pip 是 Python 的包管理工具。以下是安装 Scrapy 的步骤:
pip install Scrapy
安装完成后,你可以在命令行中输入 scrapy
来查看是否安装成功:
scrapy --version
如果成功安装,将显示 Scrapy 的版本信息。
创建一个 Scrapy 项目,你可以使用 Scrapy 提供的命令行工具 scrapy startproject
。以下步骤将引导你创建并运行一个简单的 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 的主要组件及其功能:
这些组件通过一个高度模块化的设计协同工作,使开发者能够方便地定制爬虫的行为和功能。
Scrapy 的工作流程是按步骤执行的,保证了高效的数据抓取和处理。以下是 Scrapy 的一个典型工作流程:
start_urls
列表定义。parse
方法解析数据。Item
对象并返回给引擎。以上流程在 Scrapy 中不断迭代,直到所有需要抓取的 URL 都被处理完毕。这种设计使得 Scrapy 能够高效、灵活地处理大规模的数据抓取任务。
Scrapy 项目创建步骤如下:
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 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 = 1
# 启用或禁用重试中间件 RETRY_ENABLED = True RETRY_TIMES = 5 # 设置重试次数
# 设置日志输出的级别 LOG_LEVEL = 'WARNING'
# 设置并发下载的请求数量 CONCURRENT_REQUESTS = 32
# 设置下载超时时间(秒) DOWNLOAD_TIMEOUT = 10
# 针对每个域名限制并发请求的数量 CONCURRENT_REQUESTS_PER_DOMAIN = 16
# 启用自定义的 Downloader Middleware DOWNLOADER_MIDDLEWARES = { 'example.middlewares.MyCustomDownloaderMiddleware': 543, }
# 启用或禁用 Spider Middleware SPIDER_MIDDLEWARES = { 'example.middlewares.MyCustomSpiderMiddleware': 543, }
# 启用或禁用 Item Pipeline ITEM_PIPELINES = { 'example.pipelines.MyCustomPipeline': 300, }
这些配置项可以显著影响 Scrapy 项目的行为和性能。根据实际需求调整这些配置参数,以优化爬虫的抓取效率和质量。
在 Scrapy 中,爬虫(Spider)是用于从网站中抓取数据的核心组件。为了编写一个有效的爬虫,你需要了解几个关键概念,包括 start_urls
、parse
方法和 Item
对象。以下是如何编写一个简单的 Scrapy 爬虫:
scrapy.Spider
类,必须定义 name
、start_urls
和 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 是一种强大的工具,用于在 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 选择器是另一种强大的工具,用于选择 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
类来表示你要抓取的数据结构。例如,我们抓取一个网站上的图书信息,包含书名和作者:
# example/items.py import scrapy class BookItem(scrapy.Item): title = scrapy.Field() author = scrapy.Field()
接下来,编写一个数据处理管道(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()
修改数据处理管道来调用数据库模型:
# 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'}
以上代码展示了如何处理分页和深度抓取的复杂网站结构,确保爬虫能够准确地抓取和提取所需的数据。