版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
项目6房产Requests+Parsel+MTC爬虫项目网络爬虫应用项目式教程《网络爬虫项目实战》入门篇6.1项目介绍6.2任务分解6.3项目实施目录Content6.4课后练习6.5能力拓展6.1.1
项目目标爬取某房产网站的租房页面的“区域找房”专栏,按照区域分组显示房源数,分组结果以柱状图显示。6.1.2学习目标技能目标1.能够使用Requests+Parsel采集数据2.能够使用Pandas清洗数据3.能够使用MySQL存储数据4.能够使用Flask搭建服务5.能够使用ECharts可视化数据知识目标1.熟悉数据采集过程2.熟悉数据清洗常见方法3.熟悉数据分析特点4.了解数据可视化形式素质目标1.培育项目管理能力2.培育解决实际问题能力实训目标实训项目爬取房产网站,分析和可视化区域房源数实操内容1.定位网页元素CSS选择器2.编写Requests+Parsel爬虫3.编写数据清洗代码4.使用MySQL存储数据5.搭建Flask服务6.设计和实施可视化图表6.2任务分解6.1项目目标6.3项目实施目录Content6.4课后练习6.5能力拓展6.2
任务分解从数据采集到可视化,本项目包括以下任务。数据采集标题区域价格数据清洗删除重复行抽取区信息数据分析统计区房源数数据可视化区房源数柱状图网络爬虫实战项目式教程《网络爬虫项目实战》入门篇项目6房产Requests+Parsel+MTC爬虫项目6.2任务分解6.1项目介绍6.3项目实施目录Content6.4课后练习6.5能力拓展6.3.1项目实施->数据采集(1)转到Tomcat安装目录下的bin目录,运行startup.bat后,打开Chrome,访问:50001/findhouse/index1.html,显示网站首页,代表Tomcat运行正常。如下图所示。6.3.1项目实施->数据采集(2)打开PyCharm,创建项目rent-house,选择Anaconda编译器(python.exe)。6.3.1项目实施->数据采集(3)访问:50001/findhouse/index1.html,右键打开检查->Network,查看User-Agent、cookie、referer属性值。。6.3.1项目实施->数据采集(4)在项目根目录下创建spider.py。在spider.py中,定义get_page函数,headers的“User-Agent”值使用上面RequestHeaders复制过来的内容。。#获取网页源码defget_page(url):#设置请求头信息
headers={'Cookie':'','User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/Safari/537.36'}#发送get请求
html=requests.get(url,headers=headers)#查看编码方式
encoding=get_encodings_from_content(html.text)#解码网页内容
html_doc=html.content.decode(encoding[0])#返回网页源码
returnhtml_doc6.3.1项目实施->数据采集(5)打开网站页面(:50001/findhouse/index1.html),鼠标停留在第1条租房信息,然后点击鼠标右键后,选择“检查”,查看租房信息的CSS路径,查看过程如下图所示。租房信息CSS选择器:li.listUnit-date6.3.1项目实施->数据采集Parsel使用介绍Parsel由Scrapy团队开发,可以解析HTML和XML,并支持使用XPath和CSS选择器对内容进行提取和修改,使用方法如下:导入Parsel库的Selector类,fromparselimportSelector使用Selector类,初始化一个Selector对象,如:selector=Selector(html)
在Selector对象中,使用css和xpath方法分别传入css选择器和xpath进行内容提取,如:获取到所有class为listUnit-date的li标签,可以写成:node_list=selector.css("li.listUnit-date")
使用get()或getall(),将css()函数查询到的结果转换为字符串或者列表(1)get()是将css()查询到的第一个结果转换为字符串(2)getall()是将css()查询到的结果转换为python的列表6.3.1项目实施->数据采集(6)鼠标停留在第1条租房信息中间的文本信息块部分,然后点击鼠标右键后,选择“检查”,查找房屋信息块的CSS选择器,如下图所示。房屋信息块CSS选择器:.pro-text6.3.1项目实施->数据采集(7)鼠标停留在第1条租房信息的标题部分,然后点击鼠标右键后,选择“检查”,查找标题的CSS选择器,如下图所示。标题CSS选择器:.list-pic-titleh3a::text6.3.1项目实施->数据采集(8)鼠标停留在第1条租房信息的详细信息部分,然后点击鼠标右键后,选择“检查”,查找详细信息的CSS选择器,如下图所示。详细信息CSS选择器:.list-pic-psspan::text6.3.1项目实施->数据采集(9)详细信息中含区域、房屋类型、房屋结构、面积和朝向,使用split()进行切分得到具体的分项信息,朝向信息缺失的使用空字符串赋值。(10)查找离公共交通距离和价格的CSS选择器,得到离公共交通距离的CSS选择器为“.list-pic-ad::text”,价格的CSS选择器为“.price-itemsdivspan::text”。6.3.1项目实施->数据采集(11)在spider.py中增加parse_page函数,初始化parsel.Selector()对象,获取到所有class为“listUnit-date”的li标签,从li标签中提取出租房的标题、区域、房屋类型、房屋结构、面积、朝向、交通距离和价格信息。将8个字段信息组合成字典,保存租房信息至house_raw.csv文件中。#爬取数据defparse_page(url):#获取网页
html=get_page(url)#暂停1~3秒的整数秒,时间区间:[1,3]
sleep(random.randint(1,3))#初始化parsel.Selector()对象
selector=Selector(html)#获取到所有class为listUnit-date的li标签
node_list=selector.css("li.listUnit-date")#打印获取到的标签数量
print(len(node_list))#遍历li标签,获取li标签中租房的各项信息
fornodeinnode_list:#房屋信息块
info=node.css(".pro-text")#标题
title=info.css(".list-pic-titleh3a::text").get().strip()#详细信息
detail=info.css(".list-pic-psspan::text").getall()detail[1]=re.sub("\\s+","",detail[1])contents=detail[1].split("|")#区域
district=contents[0].strip()#房屋类型
house_type=contents[1].strip()6.3.1项目实施->数据采集(11)在spider.py中增加parse_page函数,初始化parsel.Selector()对象,获取到所有class为“listUnit-date”的li标签,从li标签中提取出租房的标题、区域、房屋类型、房屋结构、面积、朝向、交通距离和价格信息。将8个字段信息组合成字典,保存租房信息至house_raw.csv文件中。#房屋结构
structure=contents[2].strip()#面积
area=contents[3].strip()#朝向
if(len(contents)<5):direction=""else:direction=contents[-1].strip()#离公共交通距离
distance=info.css(".list-pic-ad::text").getall()#替换连续空格到单个空格
if(len(distance)==0):distance=""if(len(distance)==1):distance=re.sub("\\s+","",distance[0].strip())
if(len(distance)==2):distance=re.sub("\\s+","",distance[1].strip())
#价格
price=node.css(".price-itemsdivspan::text").get()
#保存商品信息
withopen('house_raw.csv','a',newline="",encoding='utf-8')asf:
csv_write=csv.writer(f)
csv_write.writerow([title,district,house_type,structure,area,direction,distance,price])6.3.1项目实施->数据采集(12)在spider.py中定义主函数,设置爬取网站的起始页。if__name__=='__main__':#获取起始页源码
base_url=":50001/findhouse/index1.html"parse_page(base_url)6.3.1项目实施->数据采集(13)运行spider.py,结果如下图所示。城家公寓北京回龙观霍营地铁站店2楼,昌平-回龙观,公寓,一居室C房东直租+免中介费+整租房型,14M²,朝北,距离8号线霍营地铁站724米,3800元柚米寓(北京旭辉26街区店)5楼,顺义-顺义城区,公寓,复式简约一居室房型,21M²,朝南,距离15号线南法信地铁站562米,2530元魔方公寓(百子湾店)2楼,朝阳-百子湾,公寓,开间朝南房型,25M²,朝南,距离7号线百子湾地铁站803米,3990元魔方公寓(百子湾店)2楼,朝阳-百子湾,公寓,开间朝北房型,25M²,朝北,距离7号线百子湾地铁站803米,3507元城家公寓北京回龙观霍营地铁站店1楼,昌平-回龙观,公寓,一居室A房东直租+免中介费+整租房型,13M²,众多朝向,距离8号线霍营地铁站724米,3400元泊寓(亦庄店)2楼,通州-次渠,公寓,Studio房型,20M²,朝南,距离亦庄线经海路地铁站652米,2800元泊寓(亦庄店)5楼,通州-次渠,公寓,StudioL房型,25M²,朝北,距离亦庄线经海路地铁站652米,3100元6.3.1项目实施->数据采集(14)打开起始页,滑动页面到最底端,鼠标停留在最后一页的页码“5”,然后点击鼠标右键后,选择“检查”,查看页码“5”的XPath路径为“//span[@class="pageBtnWrap"]/a[last()-1]/text()”,通过对多页网址进行分析,找到网址的规律:index+数字序列。网址的规律:index+数字序列6.3.1项目实施->数据采集(15)修改spider.py,使爬虫具有翻页爬取功能。if__name__=='__main__':#获取起始页源码
base_url=":50001/findhouse/index1.html"
#parse_page(base_url)#找到总页数
first_page_doc=get_page(base_url)first_page_tree=etree.HTML(first_page_doc)page_num=first_page_tree.xpath('//span[@class="pageBtnWrap"]/a[last()-1]/text()')page_num=(int)(page_num[0])iflen(page_num)>0else0ifpage_num:page_num=(int)(page_num)#爬取多页
foriinrange(1,page_num+1):current_url=f":50001/findhouse/index{i}.html"parse_page(current_url)6.3.1项目实施->数据采集运行spider.py,打开house_raw.csv。打开文件,看到如下结果:城家公寓北京回龙观霍营地铁站店2楼,昌平-回龙观,公寓,一居室C房东直租+免中介费+整租房型,14M²,朝北,距离8号线霍营地铁站724米,3800元柚米寓(北京旭辉26街区店)5楼,顺义-顺义城区,公寓,复式简约一居室房型,21M²,朝南,距离15号线南法信地铁站562米,2530元省略柚米寓(北京旭辉26街区店)1楼,顺义-顺义城区,公寓,过道窗户型房型,24M²,朝东,距离15号线南法信地铁站562米,2575元柚米寓(北京旭辉26街区店)4楼,顺义-顺义城区,公寓,温馨复式一居房型,27M²,朝西,距离15号线南法信地铁站562米,3308元柚米寓(北京旭辉26街区店)5楼,顺义-顺义城区,公寓,空港朝北开间房型,21M²,朝北,距离15号线南法信地铁站562米,2662元6.3.2项目实施->数据清洗(1)创建data_clean.py,读入house_raw.csv到DataFrame类型。(2)完善data_clean.py,删除重复记录,剔除缺失值。(3)完善data_clean.py,从“标题”列抽取出小区和楼层。#读入csv文件到Dataframe对象labels=['标题','区域','房屋类型','房屋结构','面积','朝向','交通距离','价格']df=pd.read_csv("house_raw.csv",names=labels,encoding='utf-8')print(df.shape)print(df.head())#去重df=df.drop_duplicates()#剔除缺失值df=df.dropna()print(df.shape)#标题裂变为2列df['小区']=df['标题'].apply(lambdax:x.split('')[0])df['小区']=df['小区'].str.replace('(.*?)','')df['楼层']=df['标题'].apply(lambdax:x.split('')[1])print(df[["小区","楼层"]].head())6.3.2项目实施->数据清洗(4)完善data_clean.py,从“区域”列抽取出区和域。(5)完善data_clean.py,去除“面积”和“价格”字段的单位后缀。(6)完善data_clean.py,去除多余列并更新索引。#区域裂变为2列df['区']=df['区域'].apply(lambdax:x.split('-')[0])df['域']=df['区域'].apply(lambdax:x.split('-')[1])print(df[["区","域"]].head())#去除单位df['面积']=df['面积'].apply(lambdax:x[:-2])df['价格']=df['价格'].apply(lambdax:x[:-1])print(df[["面积","价格"]].head())#去除多余列df=df.drop(['标题','区域'],axis=1)#更新索引df=df.reset_index(drop=True)df.index=df.index+1print(df.shape)print(df.head())6.3.2项目实施->数据清洗index索引值设置成从1开始Pandas的DataFrame的index索引起始值默认为0,为了与MySQL中存储的数据主键id列保持一致,需要将index索引值设置成从1开始。(7)完善data_clean.py,保存清洗后的数据。#保存为csv文件df.to_csv(“house_clean.csv”,index_label=“id”)6.3.3项目实施->数据存储(1)使用Navicat软件,创建数据库house,如下图所示。6.3.3项目实施->数据存储(2)打开house数据库,新建查询后创建表house_infoCREATETABLEhouse_info(idINT,house_typeVARCHAR(20),structureVARCHAR(20),areaINT,directionVARCHAR(20),distanceVARCHAR(50),priceINT,addrVARCHAR(20),floorVARCHAR(20),districtVARCHAR(20),roadVARCHAR(20),PRIMARYKEY(id))charset=utf8;4.2.3MySQL存储数据(3)查看MySQL上传目录。SHOWVARIABLESLIKE'%secure_file_priv%';结果如下:(4)复制house_clean.csv到MySQL上传目录。4.2.3MySQL存储数据(5)复制house_clean.csv绝对路径到剪贴板。6.3.3项目实施->数据存储(6)将清洗后的csv文件导入house_info表中,路径中的“\”要换成“\\”,因为“\”在MySQL中是转义符。LOADDATALOCALINFILE“C:\\ProgramData\\house_clean.csv"INTOTABLEhouse_infoCHARACTERSETutf8FIELDSTERMINATEDBY','OPTIONALLYENCLOSEDBY'"'LINESTERMINATEDBY'\r\n'IGNORE1LINES(id,house_type,structure,area,direction,distance,price,addr,floor,district,road);6.3.3项目实施->数据存储(7)执行select语句,检查前5条记录。select*fromhouse_infolimit5;6.3.4项目实施->服务搭建(1)在项目根目录New->PythonPackage,创建app包。(2)在app包下New->PythonPackage,创建views包。(3)在app包下New->Directory,创建目录static,然后把echarts.min.js复制到app/static目录,当前项目结构如下图所示。6.3.4项目实施->服务搭建(4)在app包下创建extensions.py,定义db变量和config_extensions方法。#-*-coding:UTF-8-*-fromflask_sqlalchemyimportSQLAlchemydb=SQLAlchemy()defconfig_extensions(app):db.init_app(app)(5)在app/views包下创建main.py,定义blueprint变量。#-*-coding:UTF-8-*-fromflaskimportBlueprintblueprint=Blueprint("main",__name__)6.3.4项目实施->服务搭建(6)完善app/views/__init__.py,定义DEFAULT_BLUEPRINT变量。#-*-coding:UTF-8-*-fromapp.views.mainimportblueprintDEFAULT_BLUEPRINT=((blueprint,""))6.3.4项目实施->服务搭建(7)完善app/__init__.py,定义Config类、config_blueprint方法、create_app方法。#-*-coding:UTF-8-*-fromflaskimportFlaskfromapp.extensionsimportconfig_extensionsfromapp.viewsimportblueprintclassConfig:SQLALCHEMY_COMMIT_ON_TEARDOWN=TrueSQLALCHEMY_TRACK_MODIFICATIONS=FalseSQLALCHEMY_DATABASE_URI="mysql+pymysql://root:123456@:3306/house?charset=utf8"defconfig_blueprint(app):app.register_blueprint(blueprint,url_prefix="")defcreate_app(config):app=Flask(__name__)app.config.from_object(config)config_extensions(app)config_blueprint(app)returnapp6.3.4项目实施->服务搭建(8)在app包下New->PythonFile,创建manager.py。#-*-coding:UTF-8-*-fromflask_scriptimportManager,Serverfromappimportcreate_app,Configif__name__=='__main__':app=create_app(Config)manager=Manager(app)manager.add_command('runserver',Server(host='',use_debugger=True,use_reloader=True))manager.run()右键选中manager.py,选择“RunManager”菜单,运行程序,控制台出现下面结果。6.3.4项目实施->服务搭建在菜单Run->EditConfiguration,选中manager,编辑Parameters,填写“runserver”。再次右键选中manager.py,选择“RunManager”菜单,运行程序。控制台出现下面结果,代表Flask配置成功。单击“停止”按钮,停止manager运行。6.3.4项目实施->服务搭建(9)在app包下New->PythonPackage,创建包models。(10)在包app/models下创建entities.py,定义House类。#-*-coding:UTF-8-*-fromapp.extensionsimportdb#定义House类classHouse(db.Model):__tablename__='house_info'id=db.Column(db.Integer,primary_key=True)#楼层
floor=db.Column(db.String(20))#租金
price=db.Column(db.Integer)#区
district=db.Column(db.String(20))6.3.4项目实施->服务搭建(11)完善app/models/__init__.py,开放House类。(12)完善app/views/main.py,定义get_house_num_by_district和api_house_num方法。#-*-coding:UTF-8-*-fromflaskimportBlueprint,jsonifyfromsqlalchemyimportfunc,textfromapp.extensionsimportdbfromapp.modelsimportHouseblueprint=Blueprint("main",__name__)defget_house_num_by_district():rows=db.session.query(House.district,func.count().label('count')).group_by('district').order_by(text('countdesc')).limit(5)x=[]y=[]#-*-coding:UTF-8-*-from.entitiesimportHouseforrowinrows:x.append(row[0])y.append(row[1])returnx,y@blueprint.route("/api/house_num")defapi_house_num():x,y=get_house_num_by_district()returnjsonify([x,y])6.3.4项目实施->服务搭建(13)运行app/manager.py,打开Chrome,访问:5000/api/house_num,从服务器返回租房数据的列表,表示Flask连接数据库正常。6.3.5项目实施->数据可视化(1)完善app/views/main.py,增加定义house_num方法。#-*-coding:UTF-8-*-fromflaskimportBlueprint,jsonifyfromsqlalchemyimportfunc,textfromapp.extensionsimportdbfromapp.modelsimportHouseblueprint=Blueprint("main",__name__)defget_house_num_by_district():rows=db.session.query(House.district,func.count().label('count')).group_by('district').order_by(text('countdesc')).limit(5)x=[]y=[]forrowinrows:x.append(row[0])y.append(row[1])returnx,y@blueprint.route("/api/house_num")defapi_house_num():x,y=get_house_num_by_district()returnjsonify([x,y])@blueprint.route("/house_num")defhouse_num():x,y=get_house_num_by_district()returnrender_template('single_chart.html',x_data=x,y_data=y)6.3.5项目实施->数据可视化(2)在app包下New->Directory,创建templates目录。(3)在templates目录下NewHTMLFile,创建single_chart.html。<htmllang="en"><head><metacharset="UTF-8"><title>单图</title></head><body></body></html>(4)在templates目录下NewHTMLFile,创建single_chart.html。<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>单图</title>
<scriptsrc="../static/echarts.min.js"></script></head><body></body></html>6.3.5项目实施->数据可视化(5)完善single_chart.html,定义div元素和编写JS代码。JS代码中引用数据分析产生的数据,实例化ECharts图表对象,然后传给div元素显示。<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>单图</title><scriptsrc="../static/echarts.min.js"></script></head><body><!--为ECharts准备一个定义了宽高的DOM--><divid="chart1"style="width:650px;height:400px;"></div><scripttype="text/javascript">//基于准备好的dom,初始化echarts实例
varmyChart1=echarts.init(document.getElementById('chart1'));varxdata=[{%foriinx_data%}"{{i}}",{%endfor%}];varydata=[{%foriiny_data%}"{{i}}",{%endfor%}];//指定图表的配置项和数据
varoption={title:{text:'区房源数排行Top5'},tooltip:{},
xAxis:{name:'区',data:xdata,axisLabel:{interval:0,rotate:0}},yAxis:{name:'房源数'},series:[{name:'房源数',type:'bar',data:ydata.map(item=>parseFloat(item)),label:{show:true,textStyle:{fontSize:14,color:'white'}}}
]};//使用刚指定的配置项和数据显示图表。
myChart1.setOption(option);</script></body></html>
6.3.5项目实施->数据可视化打开Chrome浏览器,访问:5000/house_num,可视化结果如图所示。网络爬虫实战项目式教程《网络爬虫项目实战》入门篇项目6房产Requests+Parsel+MTC爬虫项目6.2任务分解6.1项目介绍6.4课后练习目录Content6.3项目实施6.5能力拓展6.4课后练习1.选择题(1)以下哪些是爬虫技术可能存在风险( )。A.大量占用爬取网站的资源
B.网站敏感信息的获取造成的不良后果 C.违背网站爬取设置 D.以上都是(2)下列关于Python爬虫库的功能,描述不正确的是( )。A.通用爬虫库urllib3 B.通用爬虫库Requests C.爬虫框架Scrapy D.HTML/XML解析器PycURL(3)Parsel由( )团队开发。A.Scrapy B.Python C.Java D.C(4)Parsel这个库可以解析( )。A.ASP B.JSP C.HTML和XML D.PHP(5)在Parsel库中,getall()是将css()查询到的结果转换为Python的( )。A.字符串 B.字典 C.列表 D.元组6.4课后练习2.填空题#爬取数据defparse_page(url):#获取网页源码
html=get_page(url)#初始化parsel.Selector()对象
selector=Selector(html)#获取到所有class为listUnit-date的li标签
node_list=selector.css("div.pl2")(1)技术人员想爬取图书信息后保存到books_raw.csv,请完善代码。6.4课后练习
#遍历标签,获取标签中图书的各项信息
fornodeinnode_list:#书名
title=node.css(“
").“
”#详细信息
detail=node.css("
").“
”
detail[0]=re.sub("\\s+","",detail[0])contents=detail[0].split("
")#作者
author=contents[0].strip()#出版社
publish=contents[1].strip()#日期
date=contents[2].strip()#价格
price=contents[3].strip()#评分
score=node.css("").get()#人次
num=node.css("").get()#推荐
quote=node.css("").get()#组合成字典
dict={'书名':title,'作者':,'出版社':publish,'日期':date,'价格':,'评分':,'人次':num,'推荐':quote}#保存商品信息
withopen('books_raw.csv','a',newline="",encoding='utf-8')asf:csv_write=csv.writer(f)csv_write.writerow([title,author,publish,date,price,score,num,quote])6.4课后练习
#评分
score=node.css("
").get()#人次
num=node.css
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- (2026年)乡镇卫生院年度工作计划
- 教育心理学(专升本)试卷A及答案
- 地勘掘进工安全防护评优考核试卷含答案
- 有机介质电容器纸、膜切割工岗前技术管理考核试卷含答案
- 壁球制作工安全意识竞赛考核试卷含答案
- 毛笔制作工安全技能测试知识考核试卷含答案
- 医疗器械购销员岗前诚信品质考核试卷含答案
- 植物原料制取工岗位环保责任制测试考核试卷含答案
- 人造花制作工岗中生产安全水平考核试卷含答案
- 搅拌工岗前岗位水平考核试卷含答案
- T/CSEA 49-2025微弧氧化陶瓷层
- 2026秋学期小学科普版英语四年级上册(新教材)教学计划含教学进度表
- 2026年高考化学试题(湖南卷)+答案
- 综合与实践 周长与面积的变化 课件(共21张) 苏教版数学四年级上册
- 6.1 友谊的真谛 课件(共24张)+内嵌视频
- 腰部运动康复课件
- 火力发电厂作业指导书
- 心电图机操作考核评分标准
- T∕CEA 0065-2025 电梯轿厢用空调
- 2026年精麻药品培训考试题题库及答案(完整版)
- 二次函数配方题目及答案
评论
0/150
提交评论