scripy其他

持久化

# 爬回来,解析完了,想存储,有两种方案
## 方案一:一般不用   parse必须有return值,必须是列表套字典形式--->使用命令,可以保存到json格式中,csv中scrapy crawl cnblogs -o cnbogs.json  #以json形式保存scrapy crawl cnblogs -o cnbogs.csv  #以csv形式保存#### 方案二: 我们用的,使用pipline存储---》可以存到多个位置-第一步:在item.py中写一个类class FirstscrapyItem(scrapy.Item):title = scrapy.Field()author_img = scrapy.Field()author_name = scrapy.Field()desc = scrapy.Field()url = scrapy.Field()# 博客文章内容,但是暂时没有content = scrapy.Field()-第二步:在pipline.py中写代码,写一个类:open_spide,close_spider,process_item-open_spide:开启爬虫会触发-close_spider:爬完会触发-process_ite:每次要保存一个对象会触发class FirstscrapyFilePipeline:def open_spider(self, spider):print('我开了')self.f=open('a.txt','w',encoding='utf-8')def close_spider(self, spider):print('我关了')self.f.close()# 这个很重要def process_item(self, item, spider):self.f.write(item['title']+'\n')return item-第三步:配置文件配置ITEM_PIPELINES = {"firstscrapy.pipelines.FirstscrapyFilePipeline": 300,  # 数字越小,优先级越高}-第四步:在解析方法parse中yield item对象

全站爬取cnblgos

# 继续爬取下一页
# 爬取文章详情# Request创建:在parse中,for循环中,创建Request对象时,传入meta# item对象一定要在for循环中创建,否则,当前页面都用同一个item导致同一页数据都一样yield Request(url=url, callback=self.detail_parse,meta={'item':item})
# 在parser_detail中取出来item=response.meta.get('item')
# Response对象:detail_parse中,通过response取出meta取出item,把文章详情写入def parser_detail(self,response):# content = response.css('#cnblogs_post_body').extract_first()item=response.meta.get('item')content=str(response.xpath('//div[@id="cnblogs_post_body"]').extract_first())item['content']=contentyield item

cnblogs.py

import scrapy
from scrapy import Request
# from scrapy.http.request import Request
from mysfirstscrapy.items import CnblogsItem# 爬虫类,继承了scrapy.Spider
class CnblogsSpider(scrapy.Spider):name = 'cnblogs'  # 爬虫名字allowed_domains = ['www.cnblogs.com']  # 允许爬取的域---》start_urls = ['http://www.cnblogs.com/']  # 开始爬取的地址def parse(self, response):# item = CnblogsItem()  #会有问题,是个引用类型article_list = response.xpath('//article[contains(@class,"post-item")]')  # 列表中放对象print(len(article_list))for article in article_list:item = CnblogsItem()  #每次新造一个对象title = article.xpath('.//a/text()').extract_first()desc = article.xpath('.//p[contains(@class,"post-item-summary")]/text()').extract()real_desc = desc[0].replace('\n', '').replace(' ', '')if real_desc:desc = real_descelse:real_desc = desc[1].replace('\n', '').replace(' ', '')desc = real_descauthor_img = article.xpath('.//p//img/@src').extract_first()author_name = article.xpath('.//footer//span/text()').extract_first()url = article.xpath('.//div[contains(@class,"post-item-text")]//a/@href').extract_first()item['title'] = titleitem['desc'] = descitem['author_img'] = author_imgitem['author_name'] = author_nameitem['url'] = urlyield Request(url=url,callback=self.parser_detail,meta={'item':item})  # 详情next='https://www.cnblogs.com'+response.xpath('//div[contains(@class,"pager")]/a[last()]/@href').extract_first()print(next) # 拿到地址,继续爬取,组装成一个Request对象#callback 参数是控制返回response后使用的解析方法yield Request(url=next,callback=self.parse) # 下一页地址,继续爬取,解析还是用parsedef parser_detail(self,response):# content = response.css('#cnblogs_post_body').extract_first()item=response.meta.get('item')content=str(response.xpath('//div[@id="cnblogs_post_body"]').extract_first())item['content']=contentyield item

items.py

# django模型类
class CnblogsItem(scrapy.Item):# title, desc, author_img, author_name, urltitle = scrapy.Field()desc = scrapy.Field()author_img = scrapy.Field()author_name = scrapy.Field()url = scrapy.Field()#------文章详情,暂时没有-----content = scrapy.Field()

piplines.py

class MyCnblogsMySqlPipeline:def open_spider(self, spider):self.count=0print('我开了')self.conn = pymysql.connect(user='root',  # The first four arguments is based on DB-API 2.0 recommendation.password="123",host='127.0.0.1',port=3306,database='cnblogs')self.cursor = self.conn.cursor()def close_spider(self, spider):print('我关了')self.cursor.close()self.conn.close()def process_item(self, item, spider):print('我来了-----')self.count+=1print(self.count)sql='insert into article (title,url,`desc`,author_name,author_img,content) values (%s,%s,%s,%s,%s,%s)'self.cursor.execute(sql,args=[item['title'],item['url'],item['desc'],item['author_name'],item['author_img'],item['content']])self.conn.commit()return item

settings.py

ITEM_PIPELINES = {# 'mysfirstscrapy.pipelines.MyCnblogsPipeline': 300,'mysfirstscrapy.pipelines.MyCnblogsMySqlPipeline': 301,
}

爬虫中间件和下载中间件

# 爬虫中间件:爬虫和引擎之间-用的很少,了解即可# 下载中间件:引擎和下载器之间-用的多,能干啥?-进来request对象-加代理-加cookie-加请求头-出去response对象-修改响应对象,最后进入到爬虫的parser中就是修改后的response# 爬虫中间件 (了解) middlewares.py
class MysfirstscrapySpiderMiddleware:@classmethoddef from_crawler(cls, crawler):# This method is used by Scrapy to create your spiders.s = cls()crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)return sdef process_spider_input(self, response, spider):return Nonedef process_spider_output(self, response, result, spider):for i in result:yield idef process_spider_exception(self, response, exception, spider):passdef process_start_requests(self, start_requests, spider):for r in start_requests:yield rdef spider_opened(self, spider):spider.logger.info('Spider opened: %s' % spider.name)# 下载中间件
class MysfirstscrapyDownloaderMiddleware:@classmethoddef from_crawler(cls, crawler):# This method is used by Scrapy to create your spiders.s = cls()crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)return s# 请求来了执行def process_request(self, request, spider):# 返回值可以是如下# return None:继续处理本次请求,执行执行下一个中间件的process_request#return Response:执行当前中间件的process_response回去,进入到引擎,被调度,进入第6步,返回到爬虫的解析方法中# return a Request:直接返回,给引擎,被调度,进入第2步,进入调度器等待下次被调度爬取# raise IgnoreRequest:执行 process_exceptionreturn None# 请求走了def process_response(self, request, response, spider):# 返回如下# return Response :继续往后走,进入到引擎,被调度到爬虫中解析# return Request :进入到引擎,被调度进调度器# - or raise IgnoreRequest:会执行process_exceptionreturn responsedef process_exception(self, request, exception, spider):# Called when a download handler or a process_request()# (from other downloader middleware) raises an exception.# Must either:# - return None: continue processing this exception# - return a Response object: stops process_exception() chain# - return a Request object: stops process_exception() chainpassdef spider_opened(self, spider):spider.logger.info('Spider opened: %s' % spider.name)# 在配置文件中配置

scrapy加代理,cookie,header

加代理

# 在下载中间件的def process_request(self, request, spider):写代码# 第一步:-在下载中间件写process_request方法def get_proxy(self):import requestsres = requests.get('http://127.0.0.1:5010/get/').json()if res.get('https'):return 'https://' + res.get('proxy')else:return 'http://' + res.get('proxy')def process_request(self, request, spider):request.meta['proxy'] = self.get_proxy()return None# 第二步:代理可能不能用,会触发process_exception,在里面写def process_exception(self, request, exception, spider):print('-----',request.url)  # 这个地址没有爬return request

加cookie,修改请求头,随机生成UserAgent

   #### 加cookiedef process_request(self, request, spider):print(request.cookies)request.cookies['name']='lqz'return None
    # 修改请求头def process_request(self, request, spider):print(request.headers)request.headers['referer'] = 'http://www.lagou.com'return None
    # 动态生成User-agent使用def process_request(self, request, spider):# fake_useragent模块from fake_useragent import UserAgentua = UserAgent()request.headers['User-Agent']=str(ua.random)print(request.headers)return None

scrapy集成selenium

# 使用scrapy默认下载器---》类似于requests模块发送请求,不能执行js,有的页面拿回来数据不完整

# 想在scrapy中集成selenium,获取数据更完整,获取完后,自己组装成 Response对象,就会进爬虫解析,现在解析的是使用selenium拿回来的页面,数据更完整
 

 

# 集成selenium 因为有的页面,是执行完js后才渲染完,必须使用selenium去爬取数据才完整# 保证整个爬虫中,只有一个浏览器器
# 只要爬取 下一页这种地址,使用selenium,爬取详情,继续使用原来的# 第一步:在爬虫类中写
from selenium import webdriver
class CnblogsSpider(scrapy.Spider):bro = webdriver.Chrome(executable_path='./chromedriver.exe')bro.implicitly_wait(10)def close(spider, reason):spider.bro.close() #浏览器关掉# 第二步:在中间件中def process_request(self, request, spider):# 爬取下一页这种地址---》用selenium,但是文章详情,就用原来的if 'sitehome/p' in request.url:spider.bro.get(request.url)from scrapy.http.response.html import HtmlResponseresponse = HtmlResponse(url=request.url, body=bytes(spider.bro.page_source, encoding='utf-8'))return responseelse:return None

源码去重规则(布隆过滤器)

# 如果爬取过的地址,就不会再爬了# 调度器可以去重,研究一下,如何去重的---》使用了集合# 要爬取的Request对象,在进入到scheduler调度器排队之前,先执行enqueue_request,它如果return False,这个Request就丢弃掉,不爬了----》如何判断这个Request要不要丢弃掉,执行了self.df.request_seen(request),它来决定的-----》RFPDupeFilter类中的方法----》request_seen---》会返回True或False----》如果这个request在集合中,说明爬过了,就return True,如果不在集合中,就加入到集合中,然后返回False# 调度器源码
from scrapy.core.scheduler import Scheduler# 这个方法如果return True表示这个request要爬取,如果return False表示这个网址就不爬了(已经爬过了)def enqueue_request(self, request: Request) -> bool:# request当次要爬取的地址对象if self.df.request_seen(request):# 有的请情况,在爬虫中解析出来的网址,不想爬了,就就可以指定# yield Request(url=url, callback=self.detail_parse, meta={'item': item},dont_filter=True)# 如果符合这个条件,表示这个网址已经爬过了 return Falsereturn True# self.df 去重类 是去重类的对象 RFPDupeFilter-在配置文件中如果配置了:DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'表示,使用它作为去重类,按照它的规则做去重-RFPDupeFilter的request_seendef request_seen(self, request: Request) -> bool:# request_fingerprint 生成指纹fp = self.request_fingerprint(request) #request当次要爬取的地址对象#判断 fp 在不在集合中,如果在,return Trueif fp in self.fingerprints:return True#如果不在,加入到集合,return Falseself.fingerprints.add(fp)return False# 传进来是个request对象,生成的是指纹-爬取的网址:https://www.cnblogs.com/teach/p/17238610.html?name=lqz&age=19-和         https://www.cnblogs.com/teach/p/17238610.html?age=19&name=lqz-它俩是一样的,返回的数据都是一样的,就应该是一条url,就只会爬取一次-所以 request_fingerprint  就是来把它们做成一样的(核心原理是把查询条件排序,再拼接到后面)-生成指纹,指纹是什么? 生成的指纹放到集合中去重-www.cnblogs.com?name=lqz&age=19-www.cnblogs.com?age=19&name=lqz-上面的两种地址生成的指纹是一样的# 测试指纹from scrapy.utils.request import RequestFingerprinterfrom scrapy import Requestfingerprinter = RequestFingerprinter()request1 = Request(url='http://www.cnblogs.com?name=lqz&age=20')request2 = Request(url='http://www.cnblogs.com?age=20&name=lqz')res1 = fingerprinter.fingerprint(request1).hex()res2 = fingerprinter.fingerprint(request2).hex()print(res1)print(res2)# 集合去重,集合中放 
# a一个bytes
# 假设爬了1亿条url,放在内存中,占空间非常大
a6af0a0ffa18a9b2432550e1914361b6bffcff1a
a6af0a0ffa18a9b2432550e191361b6bffc34f1a# 想一种方式,极小内存实现去重---》布隆过滤器
# 总结:scrapy的去重规则-根据配置的去重类RFPDupeFilter的request_seen方法,如果返回True,就不爬了,如果返回False就爬-后期咱们可以使用自己定义的去重类,实现去重# 更小内存实现去重-如果是集合:存的数据库越多,占内存空间越大,如果数据量特别大,可以使用布隆过滤器实现去重# 布隆过滤器:https://zhuanlan.zhihu.com/p/94668361#bloomfilter:是一个通过多哈希函数映射到一张表的数据结构,能够快速的判断一个元素在一个集合内是否存在,具有很好的空间和时间效率。(典型例子,爬虫url去重)# 原理: BloomFilter 会开辟一个m位的bitArray(位数组),开始所有数据全部置 0 。当一个元素(www.baidu.com)过来时,能过多个哈希函数(h1,h2,h3....)计算不同的在哈希值,并通过哈希值找到对应的bitArray下标处,将里面的值 0 置为 1 。# Python中使用布隆过滤器
# 测试布隆过滤器
# 可以自动扩容指定错误率,底层数组如果大于了错误率会自动扩容
# from pybloom_live import ScalableBloomFilter
# bloom = ScalableBloomFilter(initial_capacity=100, error_rate=0.001, mode=ScalableBloomFilter.LARGE_SET_GROWTH)
# url = "www.cnblogs.com"
# url2 = "www.liuqingzheng.top"
# bloom.add(url)
# bloom.add(url2)
# print(url in bloom)
# print(url2 in bloom)from pybloom_live import BloomFilterbf = BloomFilter(capacity=10)
url = 'www.baidu.com'
bf.add(url)
bf.add('aaaa')
bf.add('ggg')
bf.add('deww')
bf.add('aerqaaa')
bf.add('ae2rqaaa')
bf.add('aerweqaaa')
bf.add('aerwewqaaa')
bf.add('aerereweqaaa')
bf.add('we')print(url in bf)
print("wa" in bf)# 如果有去重的情况,就可以使用集合---》但是集合占的内存空间大,如果到了亿级别的数据量,想一种更小内存占用,而去重的方案----》布隆过滤器
# 布隆过滤器:通过不同的hash函数,加底层数组实现的极小内存去重
# python中如何使用:pybloom_live  -指定错误率-指定大小# 使用redis实现布隆过滤器-编译redis---》把第三方扩展布隆过滤器编译进去,才有这个功能-https://zhuanlan.zhihu.com/p/94668736# 重写scrapy的过滤类

分布式爬虫

# 原来scrapy的Scheduler维护的是本机的任务队列(待爬取的地址)+本机的去重队列(放在集合中)---》在本机内存中
# 如果把scrapy项目,部署到多台机器上,多台机器爬取的内容是重复的# 所以实现分布式爬取的关键就是,找一台专门的主机上运行一个共享的队列比如Redis,
然后重写Scrapy的Scheduler,让新的Scheduler到共享队列存取Request,并且去除重复的Request请求,所以总结下来,实现分布式的关键就是三点:#1、多台机器共享队列#2、重写Scheduler,让其无论是去重还是任务都去访问共享队列#3、为Scheduler定制去重规则(利用redis的集合类型)# scrapy-redis实现分布式爬虫-公共的去重-公共的待爬取地址队列#  使用步骤1 把之前爬虫类,继承class CnblogsSpider(RedisSpider):2 去掉起始爬取的地址,加入一个类属性redis_key = 'myspider:start_urls'  # redis列表的key,后期我们需要手动插入起始地址3 配置文件中配置DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"  # scrapy redis去重类,使用redis的集合去重# 不使用原生的调度器了,使用scrapy_redis提供的调度器,它就是使用了redis的列表SCHEDULER = "scrapy_redis.scheduler.Scheduler"REDIS_HOST = 'localhost'                            # 主机名REDIS_PORT = 6379                                   # 端口ITEM_PIPELINES = {# 'mysfirstscrapy.pipelines.MyCnblogsPipeline': 300,'mysfirstscrapy.pipelines.MyCnblogsMySqlPipeline': 301,'scrapy_redis.pipelines.RedisPipeline': 400,}# 再不同多台机器上运行scrapy的爬虫,就实现了分布式爬虫

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/598.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web3 开发指南:使用 NFTScan NFT API 构建一个 NFT 链上追踪器

对于大多数 Web3 团队来说,构建一个完整的链上 NFT 数据追踪系统是一项具有挑战性的任务,构建一个 NFT 链上追踪器更是如此。涉及到处理区块链上的智能合约和交易数据,并将其与外部数据源进行整合和分析工作量是十分巨大的: 区块链…

RocketMQ学习笔记(实操篇)

目录 基本操作 启动 测试 双主双从集群搭建 总体架构 工作流程 服务器环境 Host添加信息 防火墙配置 环境变量配置 创建消息存储路径 broker配置文件 修改启动脚本文件 服务启动 查看进程状态 查看日志 mqadmin管理工具 使用方式 命令介绍 集群监控平台搭…

基于深度学习的高精度刀具检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要:基于深度学习的高精度刀具检测识别系统可用于日常生活中或野外来检测与定位刀具目标,利用深度学习算法可实现图片、视频、摄像头等方式的刀具目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型…

谈谈——互联网生活中的隐私保护

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

图形编辑器开发:参考线吸附功能,让图形自动对齐

最近我给图形编辑器增加了参照线吸附功能,讲讲我的实现思路。 我正在开发的图形设计工具: https://github.com/F-star/suika 线上体验: https://blog.fstars.wang/app/suika/ 效果是被移动的图形会参考周围图形,自动与它们进行吸附…

MySQl数据库第八课-------SQL命令查询-------主要命脉

作者前言 欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com —————————————————————————————— 目录 查询数据 条件 逻辑运算符 模糊查询 范围查询 in 判断空 UNION 排序 聚合 分组:group by —————————…

c++计算贝塞尔曲线(折线平滑为曲线)坐标方法

效果可查看上一篇博文&#xff1a;js手动画平滑曲线&#xff0c;贝塞尔曲线拟合【代码】js手动画平滑曲线&#xff0c;贝塞尔曲线拟合。https://blog.csdn.net/qiufeng_xinqing/article/details/131711963?spm1001.2014.3001.5502 代码如下&#xff1a; #include <cmath&…

FPGA实验三:状态机的设计

目录 一、实验目的 二、实验要求 三、实验代码 1.design source文件部分代码 2.测试文件代码 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 &#xff08;1&#xff09;设计好序列检测器 &#xff08;2&#xff09;仿真波形&#xff08;检测11010&#xff09; 3…

【网络系统集成】路由器实验

1.实验名称:路由器RIP协议配置 2.实验目的 在PacketTracer中进行模拟实验,配置RIP协议,验证RIP协议更新时间及路由状态变化,加深对路由器RIP协议相关知识的理解与掌握。 3.实验内容 (1)拓扑结构图 (2)ip地址分配与端口分配

linux - bc 命令安装

一.引言 迁移新机器后发现没有 bc 命令&#xff0c;之前 shell 脚本的一些计算逻辑会出错&#xff0c;下面快速安装一下。 二.安装 bc 请确保在 root 权限下执行该命令&#xff1a; sudo yum install bc 出现下述界面即安装成功&#xff1a; 三.测试 bc 测试下脚本里 % 的…

快速小巧的粘贴应用程序Hasty Paste

什么是 Hasty Paste? Hasty Paste 是一个快速粘贴文本并共享的地方&#xff0c;主要用于共享调试日志等&#xff0c;以帮助开发人员提供技术支持。该项目的目标是既快又小。 命令行安装 在群晖上以 Docker 方式安装。 官方的镜像没有发布在 docker hub&#xff0c;而是在 gh…

尚医通04:Axios Node Npm bable webpack+前端工程改造

目录 本日学习 内容介绍 Axios Node NPM包管理器 Babel 模块化 Webpack 搭建前端工程 前端框架介绍 前端开发过程介绍 登录改造成本地接口 本日学习 1. 了解Axios :他是异步请求用的&#xff0c;前后端。 用于在浏览器和 Node.js 中发送 HTTP 请求。它支持从服务器…

[桌面运维] 显示器 色准,色域,色深,分辨率,带宽,刷新率的基本概念,图像呈现的基本原理

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

华为数通智选交换机S5735S-L24T4S-QA2无法SSH远程访问

以前都是按照华为S5700交换机开启SSH远程访问方法配置不同网段通过静态路由实现互通,华为S5700交换机开启ssh远程登陆,现在新买的华为数通智选交换机S5735S-L24T4S-QA2,也是按照这步骤配置,令人不解的是,竟然无法ssh访问,仔细看了配置也没有发现问题,在华为eNSP模拟器上验…

初识mysql数据库之复合查询

目录 一、多表查询的概念 二、笛卡尔积 1. 笛卡尔积的概念 2. 笛卡尔积使用案例 2.1 显示雇员名、雇员工资以及所在部门的名字 2.2 显示部门号为10的部门名&#xff0c;员工名和工资 2.3 显示所有员工的姓名、工资和工资级别 3. 自连接 3.1 自连接的概念 3.2 自连接案…

微信小程序中的条件渲染和列表渲染,wx:if ,wx:elif,wx:else,wx:for,wx:key的使用,以及block标记和hidden属性的说明

微信小程序中的条件渲染和列表渲染 1. 条件渲染1.1. 语法格式 (wx:if, wx:elif ,wx:else)1.2. block标记1.3. hidden属性1.4. wx:if 与 hidden 的对比 2. 列表渲染2.1. wx:for 语法格式 及 wx:key的使用 1. 条件渲染 1.1. 语法格式 (wx:if, wx:elif ,wx:else) <view wx:if…

MachineLearningWu_13_AGI

AGI的全称是artificial general intelligence&#xff0c;通用人工智能&#xff0c;而我们现在做的关于医学影像的分析&#xff0c;可以说完全是ANI。 而我们使用MLP对于大脑中神经网络的模拟更是完全不同于人类大脑的行为。

flutter开发实战-Running Gradle task ‘assembleDebug‘ 的解决方法

flutter开发实战-Running Gradle task ‘assembleDebug‘ 的解决方法 使用Android studio经常出现Running Gradle task ‘assembleDebug‘问题&#xff0c;记录一下解决方法。 一、在Android目录下更改build.gradle 将repositories中的google(), mavenCentral() repositori…

IIS 部署的应用禁用HTTP TRACE / TRACK方法【原理扫描】

远程Web服务器支持TRACE和/或TRACK方法。 TRACE和TRACK是用于调试Web服务器连接的HTTP方法。 直接在网站Web.config文件中进行如下操作&#xff1a;在Web.config中的<system.webServer>节点内添加以下配置即可&#xff1a; <security> <requestFiltering> &…

数据结构day2(2023.7.15)

一、Xmind整理&#xff1a; 二、课上练习&#xff1a; 练习1&#xff1a;定义车的信息&#xff1a;品牌&#xff0c;单价&#xff0c;颜色&#xff0c;车牌号 struct Car{char name[20]; //品牌int price; //单价char color[10] //颜色char id[20] //车牌…