Python爬虫之Scrapy框架基础入门
Scrapy 是一个用于Python的开源网络爬虫框架,它为编写网络爬虫来抓取网站数据并提取结构化信息提供了一种高效的方法。Scrapy可以用于各种目的的数据抓取,如数据挖掘、监控和自动化测试等。
【1】安装
pip install scrapy
安装成功如下所示:
如果安装过程出错,可以参考下面步骤解决:
# (1) pip install scrapy
# (2) 报错1: building 'twisted.test.raiser' extension
# error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
# Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
# 解决1
# http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
# Twisted‑20.3.0‑cp37‑cp37m‑win_amd64.whl
# cp是你的python版本
# amd是你的操作系统的版本
# 下载完成之后 使用pip install twisted的路径 安装
# 切记安装完twisted 再次安装scrapy# (3) 报错2 提示python -m pip install --upgrade pip
# 解决2 运行python -m pip install --upgrade pip# (4) 报错3 win32的错误
# 解决3 pip install pypiwin32# (5) anaconda
【2】基础入门
scrapy项目的结构
项目名字项目名字spiders文件夹 (存储的是爬虫文件)init自定义的爬虫文件 核心功能文件 ****************inititems 定义数据结构的地方 爬取的数据都包含哪些middleware 中间件 代理pipelines 管道 用来处理下载的数据settings 配置文件 robots协议 ua定义等
创建Scrapy项目
创建一个新的Scrapy项目,你可以在命令行中输入以下命令:
scrapy startproject myproject
这将在当前目录下创建一个名为myproject
的新目录,其中包含了Scrapy项目的结构。
scrapy startproject jane
定义Item
在Scrapy中,Item是被用来保存抓取到的数据的容器。你可以定义自己的Item类,类似于Python字典,但是提供了额外保护机制和便利方法。Item通常定义在items.py
文件中。
class ScrapyDangdangItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()# 通俗的说就是你要下载的数据都有什么# 图片src = scrapy.Field()# 名字name = scrapy.Field()# 价格price = scrapy.Field()# 详情URLdetail_url = scrapy.Field()
编写Spider
创建爬虫文件, 要在spiders文件夹中去创建爬虫文件: cd 项目的名字\项目的名字\spiders
scrapy genspider 爬虫文件的名字 要爬取网页# 示例如下
scrapy genspider baidu http://www.baidu.com
一般情况下不需要添加http协议 因为start_urls的值是根据allowed_domains修改的 所以添加了http的话 那么start_urls就需要我们手动去修改了
Spiders是定义如何抓取某个(或某些)网站的类。每个Spider负责处理一个特定的网站,或者一组相关的网页。Spiders通常位于spiders
目录下,并且以.py
文件的形式存在。
class BaiduSpider(scrapy.Spider):name = "baidu"allowed_domains = ["www.baidu.com"]start_urls = ["http://www.baidu.com"]# 是执行了start_urls之后 执行的方法 方法中的response 就是返回的那个对象# 相当于 response = urllib.request.urlopen()# response = requests.get()def parse(self, response):# 可以直接使用xpath或BS4span = response.xpath('//div[@id="filter"]/div[@class="tabs"]/a/span')[0]print('=======================')print(span.extract())
response的属性和方法
response.text 获取的是响应的字符串
response.body 获取的是二进制数据
response.xpath 可以直接是xpath方法来解析response中的内容
response.extract() 提取seletor对象的data属性值
response.extract_first() 提取的seletor列表的第一个数据
管道 (Pipeline)
管道是用来处理由Spider抓取并返回的Items的地方。你可以在pipelines.py
中定义如何处理这些Items,比如清洗、验证数据或者将它们存储到数据库中。
设置 (Settings)
Scrapy的行为可以通过修改settings.py
文件来定制,例如设置下载延迟、启用/禁用中间件、更改用户代理等。
运行 Spider
最后,你可以通过命令行运行你的Spider:
scrapy crawl baidu
【3】管道的使用
pipelines管道就是用来处理数据的,如数据清洗、处理、校验、修正以及存储。
如果想使用管道的话 那么就必须在settings中开启管道,可以定义多个管道通过优先级数值来决定执行次序。
from itemadapter import ItemAdapter
class ScrapyDangdangPipeline:# 在爬虫文件开始的之前就执行的一个方法def open_spider(self,spider):self.fp = open('book.json','w',encoding='utf-8')# item就是yield后面的book对象def process_item(self, item, spider):# 以下这种模式不推荐 因为每传递过来一个对象 那么就打开一次文件 对文件的操作过于频繁# # (1) write方法必须要写一个字符串 而不能是其他的对象# # (2) w模式 会每一个对象都打开一次文件 覆盖之前的内容# with open('book.json','a',encoding='utf-8')as fp:# fp.write(str(item))self.fp.write(str(item))return item# 在爬虫文件执行完之后 执行的方法def close_spider(self,spider):self.fp.close()import urllib.request# 多条管道开启
# (1) 定义管道类
# (2) 在settings中开启管道
# 'scrapy_dangdang_.pipelines.DangDangDownloadPipeline':301
class DangDangDownloadPipeline:def process_item(self, item, spider):url = 'http:' + item.get('src')filename = './books/' + item.get('name') + '.jpg'urllib.request.urlretrieve(url = url, filename= filename)return item
settings.py中开启管道:
ITEM_PIPELINES = {# 管道可以有很多个 那么管道是有优先级的 优先级的范围是1到1000 值越小优先级越高'scrapy_dangdang_.pipelines.ScrapyDangdangPipeline': 300,# DangDangDownloadPipeline'scrapy_dangdang_.pipelines.DangDangDownloadPipeline':301
}
【4】Scrapy中yield的使用
在 Scrapy 中,yield
有着特别重要的作用,尤其是在 Spider 类中。Scrapy 使用 yield
来返回请求(Request
)和项目(Item
),而不需要将它们全部加载到内存中。这使得 Scrapy 可以高效地处理大量的页面和数据。
在 Scrapy 中,yield
主要用于以下两个场景:
1. 返回 Request
对象
当您需要从一个页面抓取多个链接并发送请求时,可以使用 yield
来逐个返回 Request
对象。Scrapy 会自动处理这些请求,并将响应传递给指定的回调函数。
class DangSpider(scrapy.Spider):name = 'dang'start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:detail_url = 'http:' + li.xpath('./a/@href').get()if detail_url:yield scrapy.Request(detail_url, callback=self.parse_detail)def parse_detail(self, response):review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()self.logger.info(f"当前图书评论数为: {review_count}")
在这个例子中,parse
方法会遍历列表页中的每个书籍链接,并使用 yield
逐个返回 Request
对象。Scrapy 会依次处理这些请求,并将详情页的响应传递给 parse_detail
方法。
2. 返回 Item
对象
当您从页面中提取数据并构建 Item
时,可以使用 yield
将 Item
返回给 Scrapy 的管道进行进一步处理(如保存到数据库、导出为文件等)。
class DangSpider(scrapy.Spider):name = 'dang'start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:src = li.xpath('.//img/@data-original').get() or li.xpath('.//img/@src').get()name = li.xpath('.//img/@alt').get()price = li.xpath('.//p[@class="price"]/span[1]/text()').get()detail_url = 'http:' + li.xpath('./a/@href').get()if not src or not name or not price or not detail_url:self.logger.warning("缺少关键信息,跳过此条目")continuebook_info = {'src': src,'name': name,'price': price,'detail_url': detail_url}yield scrapy.Request(detail_url, callback=self.parse_detail, cb_kwargs={'book_info': book_info})def parse_detail(self, response, book_info):review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()book_info['review_count'] = review_countbook_item = ScrapyDangdangItem(**book_info)self.logger.info(f"抓取到完整图书信息: {book_item}")yield book_item
在这个例子中,parse_detail
方法会从详情页提取评论数,并将其添加到 book_info
字典中。然后,它会创建一个 ScrapyDangdangItem
实例,并使用 yield
将其返回给 Scrapy 的管道。
【5】parse方法之间如何传参?
比如,需要先获取分类列表,然后获取每一个详情,最后整合获取得到book信息。
在 Scrapy 中,通常情况下,您会希望将从详情页获取的数据(如评论数)与列表页获取的数据(如书名、价格等)结合起来,形成一个完整的 Item。为了实现这一点,您可以使用 Request
的 meta
参数来传递数据,或者使用 cb_kwargs
参数(Scrapy 1.7+)来传递关键字参数。
方法 1: 使用 meta
参数
meta
参数允许您在请求之间传递数据。您可以在 parse
方法中将书籍的基本信息(如书名、价格、图片链接等)通过 meta
传递给 parse_detail
方法,然后在 parse_detail
中提取评论数并返回一个完整的 Item。
修改后的代码:
import scrapy
from ..items import ScrapyDangdangItem # 确保这里正确导入了Itemclass DangSpider(scrapy.Spider):name = 'dang'allowed_domains = ['dangdang.com'] # 放宽域名限制start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']base_url = 'http://category.dangdang.com/pg'page = 1def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:src = li.xpath('.//img/@data-original').get() or li.xpath('.//img/@src').get()name = li.xpath('.//img/@alt').get()price = li.xpath('.//p[@class="price"]/span[1]/text()').get()detail_url = 'http:' + li.xpath('./a/@href').get()if not src or not name or not price or not detail_url:self.logger.warning("缺少关键信息,跳过此条目")continue# 构建基础的图书信息book_info = {'src': src,'name': name,'price': price,'detail_url': detail_url}# 发送详情页请求,并通过 meta 传递图书信息yield scrapy.Request(detail_url, callback=self.parse_detail, meta={'book_info': book_info})def parse_detail(self, response):# 从 meta 中获取图书信息book_info = response.meta['book_info']# 提取评论数review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()# 将评论数添加到图书信息中book_info['review_count'] = review_count# 创建并返回完整的 Itembook_item = ScrapyDangdangItem(**book_info)self.logger.info(f"抓取到完整图书信息: {book_item}")yield book_item
方法 2: 使用 cb_kwargs
参数 (Scrapy 1.7+)
cb_kwargs
是 Scrapy 1.7 版本引入的一个新特性,它允许您直接在 Request
中传递关键字参数,而不需要通过 meta
。这种方式更加直观和简洁。
修改后的代码:
import scrapy
from ..items import ScrapyDangdangItem # 确保这里正确导入了Itemclass DangSpider(scrapy.Spider):name = 'dang'allowed_domains = ['dangdang.com'] # 放宽域名限制start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']base_url = 'http://category.dangdang.com/pg'page = 1def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:src = li.xpath('.//img/@data-original').get() or li.xpath('.//img/@src').get()name = li.xpath('.//img/@alt').get()price = li.xpath('.//p[@class="price"]/span[1]/text()').get()detail_url = 'http:' + li.xpath('./a/@href').get()if not src or not name or not price or not detail_url:self.logger.warning("缺少关键信息,跳过此条目")continue# 构建基础的图书信息book_info = {'src': src,'name': name,'price': price,'detail_url': detail_url}# 发送详情页请求,并通过 cb_kwargs 传递图书信息yield scrapy.Request(detail_url, callback=self.parse_detail, cb_kwargs={'book_info': book_info})def parse_detail(self, response, book_info):# 提取评论数review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()# 将评论数添加到图书信息中book_info['review_count'] = review_count# 创建并返回完整的 Itembook_item = ScrapyDangdangItem(**book_info)self.logger.info(f"抓取到完整图书信息: {book_item}")yield book_item
关键点解释
-
meta
参数:- 在
parse
方法中,我们构建了一个包含图书基本信息的字典book_info
。 - 使用
meta
参数将book_info
传递给parse_detail
方法。 - 在
parse_detail
中,通过response.meta['book_info']
获取传递过来的图书信息。
- 在
-
cb_kwargs
参数:- 在
parse
方法中,我们同样构建了一个包含图书基本信息的字典book_info
。 - 使用
cb_kwargs
参数将book_info
作为关键字参数传递给parse_detail
方法。 - 在
parse_detail
中,直接通过函数参数book_info
获取传递过来的图书信息。
- 在
-
合并数据:
- 在
parse_detail
中,我们提取了评论数,并将其添加到book_info
字典中。 - 最后,我们创建了一个
ScrapyDangdangItem
实例,并将其返回给 Scrapy 的管道进行处理。
- 在
【6】管道中使用pymysql存储数据
from itemadapter import ItemAdapterclass ScrapyReadbookPipeline:def open_spider(self,spider):self.fp = open('book.json','w',encoding='utf-8')def process_item(self, item, spider):self.fp.write(str(item))return itemdef close_spider(self,spider):self.fp.close()# 加载settings文件
from scrapy.utils.project import get_project_settings
import pymysqlclass MysqlPipeline:def open_spider(self,spider):settings = get_project_settings()self.host = settings['DB_HOST']self.port =settings['DB_PORT']self.user =settings['DB_USER']self.password =settings['DB_PASSWROD']self.name =settings['DB_NAME']self.charset =settings['DB_CHARSET']self.connect()def connect(self):self.conn = pymysql.connect(host=self.host,port=self.port,user=self.user,password=self.password,db=self.name,charset=self.charset)self.cursor = self.conn.cursor()def process_item(self, item, spider):sql = 'insert into book(name,src) values("{}","{}")'.format(item['name'],item['src'])# 执行sql语句self.cursor.execute(sql)# 提交self.conn.commit()return itemdef close_spider(self,spider):self.cursor.close()self.conn.close()
数据库配置信息在settings.py中:
【7】日志级别与存储路径
settings.py中配置日志级别与路径即可:
# 指定日志的级别
# LOG_LEVEL='WARNING'LOG_FILE = 'logdemo.log'
【8】POST请求
如下所示是GET请求:
yield scrapy.Request(url=detail_url, callback=self.parse_detail)
重写start_requests方法使用FormRequest发送POST请求
class TestpostSpider(scrapy.Spider):name = 'testpost'allowed_domains = ['https://fanyi.baidu.com/sug']# post请求 如果没有参数 那么这个请求将没有任何意义# 所以start_urls 也没有用了# parse方法也没有用了# start_urls = ['https://fanyi.baidu.com/sug/']## def parse(self, response):# passdef start_requests(self):url = 'https://fanyi.baidu.com/sug'data = {'kw': 'final'}yield scrapy.FormRequest(url=url,formdata=data,callback=self.parse_second)def parse_second(self,response):content = response.textobj = json.loads(content,encoding='utf-8')print(obj)
【9】与xpath结合使用
如下图所示,想要提取week内容
dl_weather = response.xpath('//dl[@class="weather_info"]')
dl_weather_xpath = dl_weather.xpath('//dd[@class="week"]')
# 这里获取的是Selector 数组,data为目标html 元素
print("dl_weather.xpath('//dd[@class='week\"]')", dl_weather_xpath) # 这里获取的是Selector 数组,data为目标html 元素的文本内容
weather_xpath = dl_weather.xpath('//dd[@class="week"]/text()')
print("dl_weather.xpath('//dd[@class='week\"]/text()')", weather_xpath)# 这里获取的是文本数组
week__extract = weather_xpath.extract()# extract_first表示获取第一个文本节点
print("weather_xpath.extract_first() :",weather_xpath.extract_first())print("weather_xpath.extract() :",week__extract)
结果如下所示:
dl_weather.xpath('//dd[@class='week"]') [<Selector query='//dd[@class="week"]' data='<dd class="week">2024年12月16日\u3000星期一\u3000甲辰年冬...'>]dl_weather.xpath('//dd[@class='week"]/text()') [<Selector query='//dd[@class="week"]/text()' data='2024年12月16日\u3000星期一\u3000甲辰年冬月十六 '>]
weather_xpath.extract_first() : 2024年12月16日 星期一 甲辰年冬月十六
weather_xpath.extract() : ['2024年12月16日\u3000星期一\u3000甲辰年冬月十六 ']
{'date': ['2024年12月16日\u3000星期一\u3000甲辰年冬月十六 ']}
相关文章:

Python爬虫之Scrapy框架基础入门
Scrapy 是一个用于Python的开源网络爬虫框架,它为编写网络爬虫来抓取网站数据并提取结构化信息提供了一种高效的方法。Scrapy可以用于各种目的的数据抓取,如数据挖掘、监控和自动化测试等。 【1】安装 pip install scrapy安装成功如下所示:…...

spring cloud contract mq测试
对于spring cloud contract的环境配置和部署,请看我之前的文章。 一 生产者测试 测试生产者是否发送出消息,并测试消息内容是否正确。 编写测试合同 测试基类(ContractTestBase)上面要添加下面注解 SpringBootTest AutoConfig…...

Axure原型设计技巧与经验分享
AxureRP作为一款强大的原型设计工具,凭借其丰富的交互设计能力和高保真度的模拟效果,赢得了众多UI/UX设计师、产品经理及开发人员的青睐。本文将分享一些Axure原型设计的实用技巧与设计经验,帮助读者提升工作效率,打造更加流畅、用…...

计算机网络之王道考研读书笔记-1
第 1 章 计算机网络体系结构 1.1 计算机网络概述 1.1.1 计算机网络概念 internet(互连网):泛指由多个计算机网络互连而成的计算机网络。这些网络之间可使用任意通信协议。 Internet(互联网或因特网):指当前全球最大的、开放的、由众多网络和路由器互连…...

服务器限制某个端口只允许特定IP访问(处理第三方依赖漏洞)
最近项目部署之后,有些客户开始进行系统系统漏洞扫描,其中出现问题多的一个就是我们项目所依赖的Elasticsearch(es检索服务),很容易就被扫出来各种高危漏洞,而且这些漏洞我们在处理起来是很棘手的ÿ…...

JavaScript--原型与原型链
在JavaScript中,原型(prototype)是一个非常重要且独特的概念,它在对象创建和继承方面发挥着关键作用。理解原型及其相关的机制有助于更好地理解JavaScript的对象模型,以及如何设计和使用对象和继承。 JavaScript–原型…...

hive—常用的日期函数
目录 1、current_date 当前日期 2、now() 或 current_timestamp() 当前时间 3、datediff(endDate, startDate) 计算日期相差天数 4、months_between(endDate, startDate) 日期相差月数 5、date_add(startDate, numDays) 日期加N天 6、date_sub(startDate, numDays) 日期减…...

HTML零基础入门教学
目录 一. HTML语言 二. HTML结构 三. HTML文件基本结构 四. 准备开发环境 五. 快速生成代码框架 六. HTML常见标签 6.1 注释标签 6.2 标题标签:h1-h6 6.3 段落标签:p 6.4 换行标签:br 6.5 格式化标签 6.6 图片标签&a…...
vue3 父组件调用子组件 el-drawer 抽屉
之前 Vue3 只停留在理论,现在项目重构,刚好可以系统的实战一下,下面是封装了一个抽屉表单组件,直接在父组件中通过调用子组件的方法打开抽屉: 父组件: <template><div id"app"><…...
Java中常用算法之选择排序算法
一.选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理是每次从未排序部分选择最小(或最大)的元素,并将其放到已排序部分的末尾。以下是用Java实现选择排序的代码及其详细讲解。 二.选择排序代码 publ…...

UNIX简史
从1991年Linux出现至今,由于众多IT巨头以及技术社区的推动,Linux已经成为非常成熟、可用于各种关键领域的操作系统,适当了解其发展历史,对于理顺其技术流派、从而更好地学习和使用Linux具有重要意义。由于其基于UNIX系统二十多年的…...
React和Vue中暴露子组件的属性和方法给父组件用,并且控制子组件暴露的颗粒度的做法
React 在 React 中,forwardRef 是一种高级技术,它允许你将 ref 从父组件传递到子组件,从而直接访问子组件的 DOM 节点或公开的方法。这对于需要操作子组件内部状态或 DOM 的场景非常有用。为了使子组件能够暴露其属性和方法给父组件…...
uniapp 常用的指令语句
uniapp 是一个使用 Vue.js 开发的跨平台应用框架,因此,它继承了 Vue.js 的大部分指令。以下是一些在 uniapp 中常用的 Vue 指令语句及其用途: v-if / v-else-if / v-else 条件渲染。v-if 有条件地渲染元素,v-else-if 和 v-else 用…...

python学opencv|读取图像(十四)BGR图像和HSV图像通道拆分
【1】引言 前序已经对BGR图像和HSV图像的转换进行了基本讨论,相关文章链接为: python学opencv|读取图像(十二)BGR图像转HSV图像-CSDN博客 python学opencv|读取图像(十三)BGR图像和HSV图像互相转换深入-C…...
C# 结构体和类
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、类(Class)二、结构体(Struct)示例代码(定义类和结构体)类的继承代码示例(…...

D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。
概述: D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。 主要特点: ● 高精度基准电路 ● 定时闩锁、短路保护电路 ● 低电压输入时误操作保护电路 ● 输出基准电压(2.5V) ● 超过工作范围能进行自动校…...
题目 1738: 排序
题目 1738: 排序 时间限制: 2s 内存限制: 96MB 提交: 14351 解决: 3477 题目描述 对输入的n个数进行排序并输出。 输入格式 输入的第一行包括一个整数n(1<n<100)。 接下来的一行包括n个整数。 输出格式 可能有多组测试数据,对于每组数据,将排序后…...

爬虫逆向学习(十四):分享一下某数通用破解服务开发经验
阅前须知 这篇博客不是教大家怎么实现的,而且告知大家有这个东西,或者说一种趋势,借此分享自己大致的实现经验。具体的实现我也不好整理,毕竟是在别人的基础上缝缝补补。 前言 使用补环境方式破解过某数的同学都知道࿰…...
《Vue进阶教程》第十一课:响应式系统介绍
1 什么是响应式 当数据改变时, 引用数据的函数会自动重新执行 2 手动完成响应过程 首先, 明确一个概念: 响应式是一个过程, 这个过程存在两个参与者: 一方触发, 另一方响应 比如说, 我们家小胖有时候不乖, 我会打他, 他会哭. 这里我就是触发者, 小胖就是响应者 同样, 所谓…...
rpc设计的再次思考20251215(以xdb为核心构建游戏框架)
1.服务提供者注册的方式 // 表明这是一个服务提供者,ServerType 和 ServerId从application.properties中读取 // 而且只有当当前服务是Game时,才生效。 或者 条件注解??? RpcProvider(typeServerType.Game) public class GameProvider{MsgReceiver…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...