Scrapy教程涵盖了从环境搭建到基本编写,再到进阶技巧和实战案例的全方位内容,帮助你掌握Scrapy的强大功能。文章详细介绍了如何安装Python和Scrapy,创建Scrapy项目及基本文件结构,以及编写和运行Scrapy爬虫的具体步骤。此外,还深入讲解了使用Scrapy中间件、处理请求与响应等高级技术。
Scrapy简介Scrapy是什么
Scrapy是一个高度可扩展的Python语言编写的数据抓取和处理框架。它主要用于从网站上提取数据并将其结构化,通常用于构建网络爬虫。Scrapy采用了异步模型和基于Twisted事件循环的架构,具有较高的性能和伸缩性。Scrapy的核心设计目标是将网络爬虫的各个部分解耦,使得组件可以独立替换或升级,从而更好地适应各种数据抓取需求。
Scrapy的优点
- 高效能:Scrapy使用Twisted异步网络库,可以同时发起多个请求,从而提高了爬虫的抓取速度。
- 高扩展性:Scrapy采用了模块化的设计,允许用户根据自己的需求自定义中间件、管道等组件。
- 简洁的API:Scrapy使用了简单明了的API,使得编写爬虫代码变得更加容易。
- 强大的功能:Scrapy支持cookies、JavaScript渲染、登录验证等多种高级功能。
- 丰富的功能组件:Scrapy内置了多种中间件和管道,可以方便地扩展和定制爬虫。
Scrapy适用场景
- 数据抓取:从网站上抓取特定类型的数据,如新闻、产品信息、价格等。
- 信息挖掘:从大量的网页中提取有价值的信息,进行深度分析。
- 网站监控:定期监控特定网站,以获得实时更新。
- 搜索引擎抓取:为搜索引擎提供数据抓取服务,提升搜索引擎的覆盖率。
- 数据存储:将抓取的数据存储到数据库中,以便后续处理和分析。
- 自动化测试:模拟用户行为,进行网站测试和验证。
- 数据清洗:从杂乱的数据中提取有用的信息,清洗数据,以提高数据质量。
安装Python
访问Python官方网站(https://www.python.org/),下载最新版本的Python安装包。选择对应操作系统的安装包,下载后双击安装程序。在安装过程中,确保选中“Add Python to PATH”选项。安装完成后,可以验证Python是否安装成功,打开命令行界面,运行如下命令:
python --version
安装Scrapy
安装Scrapy需要使用Python的包管理工具pip。首先确保pip已经安装,然后使用pip安装Scrapy。
- 打开命令行界面,输入以下命令,更新pip到最新版本:
pip install --upgrade pip
- 使用pip安装Scrapy:
pip install scrapy
验证Scrapy是否安装成功
在命令行中输入以下命令来验证Scrapy是否安装成功:
scrapy --version
如果Scrapy安装成功,命令行将显示Scrapy的版本信息。
Scrapy项目的创建与结构创建Scrapy项目
创建Scrapy项目需要使用Scrapy自带的命令行工具。
- 打开命令行界面,输入以下命令来创建新的Scrapy项目:
scrapy startproject myproject
- 进入新创建的项目目录:
cd myproject
项目文件结构解析
Scrapy项目的基本结构如下:
myproject/
scrapy.cfg # 项目配置文件
myproject/
__init__.py
items.py # 定义存储数据的结构
pipelines.py # 数据处理管道
settings.py # 项目配置文件
spiders/ # 爬虫文件夹
__init__.py
myspider.py # 第一个爬虫文件
- scrapy.cfg:Scrapy项目的配置文件。
- myproject:Scrapy项目的主目录。
- items.py:定义存储数据的结构。例如,定义一个简单的项目数据结构:
# items.py
import scrapy
class MyprojectItem(scrapy.Item):
# 定义数据字段
title = scrapy.Field()
url = scrapy.Field()
content = scrapy.Field()
- **pipelines.py**:用于处理数据的管道。例如,可以定义一个简单的数据处理管道:
# pipelines.py
class MyprojectPipeline:
def process_item(self, item, spider):
# 处理每个抓取到的item
print(f"Processing item: {item}")
return item
- **settings.py**:项目配置文件,用于全局配置Scrapy项目。例如,设置请求超时时间:
# settings.py
# 设置请求超时时间
DOWNLOAD_TIMEOUT = 10
- **spiders**:存放爬虫的目录。
- **myspider.py**:第一个爬虫文件。例如,创建一个简单的爬虫:
# myspider.py
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
allowed_domains = ['example.com']
start_urls = ['http://example.com']
def parse(self, response):
# 解析页面内容
print('Got a response from:', response.url)
Scrapy爬虫的基本编写
编写爬虫的步骤
编写Scrapy爬虫需要遵循以下步骤:
- 定义爬虫类:创建一个新的Python类并继承
scrapy.Spider
类。 - 定义爬虫名称:在爬虫类中定义
name
属性,表示爬虫的名称。 - 定义允许的域名:在爬虫类中定义
allowed_domains
属性,表示爬虫允许爬取的域名列表。 - 定义起始的URL列表:在爬虫类中定义
start_urls
属性,表示爬虫开始爬取的URL列表。 - 定义解析函数:在爬虫类中定义
parse
方法,用于解析每个页面的内容并提取所需的数据。
解析页面信息
Scrapy提供了强大的选择器功能,使得解析页面内容变得更加简单。选择器可以方便地提取HTML页面中的文本、属性等信息。
- 创建Spider类:首先定义一个Spider类,继承自
scrapy.Spider
:
from scrapy import Spider
class MySpider(Spider):
name = 'my_spider'
allowed_domains = ['example.com']
start_urls = ['http://example.com']
- 定义解析函数:定义
parse
方法,这是爬虫默认的解析函数。在parse
方法中,通过response
对象调用选择器来解析页面内容:
def parse(self, response):
# 从响应中提取标题
title = response.css('title::text').get()
print(f"Title: {title}")
# 提取页面中所有的链接
links = response.css('a::attr(href)').getall()
for link in links:
print(f"Found link: {link}")
- 发送新的爬取请求:如果需要继续抓取其他页面,可以使用
response.follow
方法发送新的请求:
def parse(self, response):
# 提取每个链接并发送新的请求
for link in response.css('a::attr(href)').getall():
yield response.follow(link, self.parse)
- 提取数据并存储:使用
yield
关键字提取数据并保存为Item。例如,定义一个MyItem
类:
from scrapy.item import Item, Field
class MyItem(Item):
title = Field()
url = Field()
content = Field()
然后在parse
方法中使用yield
生成Item:
def parse(self, response):
item = MyItem()
item['title'] = response.css('title::text').get()
item['url'] = response.url
item['content'] = response.css('div.content::text').get()
yield item
- 处理异常:在定义爬虫时,可以处理各种异常情况,例如超时、网络错误等:
from scrapy.exceptions import CloseSpider
def parse(self, response):
try:
# 尝试解析页面
title = response.css('title::text').get()
print(f"Title: {title}")
except Exception as e:
# 处理异常情况
print(f"Exception: {e}")
raise CloseSpider("Encountered an exception")
Scrapy进阶技巧
使用Scrapy中间件
Scrapy中间件是一种可以拦截请求、响应的机制,可以在请求和响应之间处理数据。Scrapy提供了丰富的中间件,涵盖了请求、响应、下载、调度等多个环节。
- 定义自定义中间件:创建一个Python类来实现中间件功能,该类需要定义
process_request
、process_response
等方法:
from scrapy import signals
from scrapy.http import HtmlResponse
class MyMiddleware:
@classmethod
def from_crawler(cls, crawler):
# 初始化中间件
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def spider_opened(self, spider):
# 蜘蛛打开时的操作
print(f"Spider {spider.name} opened")
def process_request(self, request, spider):
# 处理请求
print(f"Processing request: {request.url}")
return None # 继续处理正常请求
def process_response(self, request, response, spider):
# 处理响应
print(f"Processing response: {response.url}")
return response # 返回原始响应或修改后的响应
- 启用中间件:在
settings.py
中启用自定义中间件:
# settings.py
DOWNLOADER_MIDDLEWARES = {
'myproject.my_middleware.MyMiddleware': 543,
}
深入了解Scrapy的请求与响应
Scrapy提供了丰富的API来处理请求和响应。请求和响应对象提供了各种方法来访问和操作HTTP请求和响应数据。例如,可以使用request.meta
来传递额外的元数据信息,或者使用response.meta
来读取元数据信息。
- 请求元数据:在发送请求时,可以通过
request.meta
传递额外的元数据信息:
def parse(self, response):
for link in response.css('a::attr(href)').getall():
yield scrapy.Request(link, callback=self.parse, meta={'custom': 'metadata'})
- 读取响应元数据:在解析响应时,可以通过
response.meta
读取元数据信息:
def parse(self, response):
custom_data = response.meta.get('custom', 'default_value')
print(f"Custom data: {custom_data}")
# 继续解析页面内容
- 自定义请求头:可以在请求中添加自定义请求头信息:
def parse(self, response):
headers = {
'User-Agent': 'MyCustomUserAgent',
'Referer': response.url
}
for link in response.css('a::attr(href)').getall():
yield scrapy.Request(link, callback=self.parse, headers=headers)
- 处理重定向:Scrapy默认处理重定向,但可以通过
dont_filter
参数禁用重定向过滤:
def parse(self, response):
yield scrapy.Request(
response.url,
callback=self.parse_redirected,
dont_filter=True # 禁用重定向过滤
)
def parse_redirected(self, response):
print(f"Redirected to: {response.url}")
- 异步请求:Scrapy支持异步请求,可以使用
asyncio
库配合async def
定义异步解析函数:
import asyncio
import aiohttp
async def parse(self, response):
async with aiohttp.ClientSession() as session:
async with session.get(response.url) as resp:
text = await resp.text()
print(f"Got async response: {text}")
Scrapy实战案例
爬取网站案例
以爬取一个简单的新闻网站为例,展示如何使用Scrapy爬虫抓取网页信息。
- 定义Item:首先定义一个
NewsItem
类,用于存储新闻信息:
from scrapy.item import Item, Field
class NewsItem(Item):
title = Field()
url = Field()
content = Field()
publish_time = Field()
- 编写爬虫:创建一个爬虫类,继承自
scrapy.Spider
,定义爬虫名称、允许的域名、起始URL和解析函数:
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from myproject.items import NewsItem
class NewsSpider(CrawlSpider):
name = 'news_spider'
allowed_domains = ['example.com']
start_urls = ['http://example.com/news']
rules = (
Rule(LinkExtractor(allow=r'news/\d+'), callback='parse_item', follow=True),
)
def parse_item(self, response):
item = NewsItem()
item['title'] = response.css('h1::text').get()
item['url'] = response.url
item['content'] = response.css('.content ::text').getall()
item['publish_time'] = response.css('.publish-time::text').get()
yield item
- 运行爬虫:在命令行中运行爬虫:
scrapy crawl news_spider
数据存储与处理方法
在Scrapy中,可以通过管道将抓取的数据存储到不同的存储介质中,例如数据库或文件系统。
- 定义数据处理管道:创建一个管道类,实现数据处理逻辑:
from scrapy import Item, Field, signals
from scrapy.exceptions import DropItem
from myproject.items import NewsItem
class NewsPipeline:
def process_item(self, item, spider):
# 处理每个新闻项
if not item['title']:
raise DropItem("Missing title in %s" % item)
return item
- 配置管道:在
settings.py
中启用管道:
# settings.py
ITEM_PIPELINES = {
'myproject.pipelines.NewsPipeline': 300,
}
- 将数据存储到数据库:可以将新闻数据存储到MySQL数据库中:
import pymysql
class MySqlPipeline:
def __init__(self):
self.db = pymysql.connect(
host='localhost',
user='root',
password='password',
database='scrapydb'
)
self.cursor = self.db.cursor()
def process_item(self, item, spider):
sql = 'INSERT INTO news (title, url, content, publish_time) VALUES (%s, %s, %s, %s)'
values = (item['title'], item['url'], item['content'], item['publish_time'])
self.cursor.execute(sql, values)
self.db.commit()
return item
def close_spider(self, spider):
self.db.close()
- 配置管道顺序:在
settings.py
中配置管道顺序:
# settings.py
ITEM_PIPELINES = {
'myproject.pipelines.NewsPipeline': 300,
'myproject.pipelines.MySqlPipeline': 800,
}
共同學習,寫下你的評論
評論加載中...
作者其他優質文章