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。
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
类,它包含 title
、author
、price
和 publish_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
Request
和 Response
是 Scrapy 中用于处理网络请求和响应的两个核心对象。
- Request:
Request
对象表示一个网络请求,它包含请求的 URL、HTTP 方法、回调函数等信息。Scrapy 会根据这些信息向指定的 URL 发出请求。 - Response:
Response
对象表示一个网络响应,它包含从请求 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.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
)进行打包和发布,使得项目可以被部署到生产环境。以下是一个简单的打包和发布流程:
-
安装
setuptools
:确保已经安装了setuptools
:pip install setuptools
-
创建
setup.py
文件:在项目根目录下创建一个setup.py
文件,定义项目的元数据和依赖项:from setuptools import setup, find_packages setup( name='myproject', version='0.1', packages=find_packages(), install_requires=[ 'Scrapy', # 其他依赖项 ] )
-
打包:使用
setuptools
打包项目:python setup.py sdist bdist_wheel
这将生成一个源代码包和一个二进制包。
-
发布到 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 项目的日常维护和更新包括以下几个方面:
-
版本管理:确保项目的版本号在每次更新时都正确更新。可以在
setup.py
文件中指定版本号。 -
依赖更新:定期检查项目的依赖项,并更新到最新版本。可以在
setup.py
文件的install_requires
列表中更新依赖项。 -
代码审查:定期进行代码审查,确保代码的可读性和可维护性。可以使用代码审查工具如
flake8
或pylint
。 - 单元测试:编写单元测试以确保代码的正确性和稳定性。可以在
tests
目录下创建测试文件,并使用pytest
或unittest
运行测试。
例如,创建一个简单的单元测试文件 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_REQUESTS
、CONCURRENT_REQUESTS_PER_DOMAIN
和 CONCURRENT_REQUESTS_PER_IP
参数,找到适当的并发设置,以避免被目标网站封禁。
例如,限制每个域名的最大并发请求数:
CONCURRENT_REQUESTS_PER_DOMAIN = 5
问题:Scrapy 中间件不生效
解决方案:确保在 settings.py
文件中正确配置了中间件,并且中间件类实现了 process_request
或 process_response
方法。
例如,确保中间件类实现了 process_request
方法:
import scrapy
class CustomMiddleware(scrapy.downloadermiddlewares.DownloaderMiddleware):
def process_request(self, request, spider):
request.headers['Custom-Header'] = 'Custom-Value'
return request
共同学习,写下你的评论
评论加载中...
作者其他优质文章