|
大家好!我是爱摸鱼的小鸿,关注我,收看每期的编程干货。本篇文章将详细介绍Python高性能Web异步框架Sanic的各功能,并通过实战将爬虫(Spiders)模块+视图(Views)模块+路由(Routers)模块+模型(Models)模块结合形成一个各模块独立、高性能、可读性高、可扩展性高、具有精美的接口文档、易于后期维护的爬虫API项目,并部署在Ubuntu服务器上供团队调用。目录一、Sanic简介及特性二、Sanic各功能测试三、爬虫API实战项目四、服务器部署及接口性能测试五、作者Info一、Sanic简介及特性说到PythonWeb框架,你可能会想到Flask、Django、Tornado、FastAPI这些;而本文将向大家介绍另一个PythonWeb框架——Sanic。它是一个Python3.8+Web服务器和Web框架,旨在快速运行。它允许使用Python3.5中添加的async/await语法,这使您的代码非阻塞且快速。应用场景如果你希望快速搭建一个小型的API项目,又对速度有非常大的需求,那Sanic无疑是你的天选框架,很哇塞的哟!Sanic特性直接支持生产环境部署高度可扩展内置快速网络服务器具有异步支持使用Redoc、Swagger的OpenAPI文档CORS保护等Sanic安装pipinstallsanic-ihttps://pypi.doubanio.com/simple1默认安装最新版,也可指定你需要的版本二、Sanic各功能测试快速上手先来快速构建一个简单的PythonWeb应用:fromsanicimportSanicfromsanic.responseimportjsonfromdatetimeimportdatetimeimportmultiprocessingapp=Sanic("SanicAPP")HOST="localhost"PORT=7777app.config.FALLBACK_ERROR_FORMAT='json'app.config.ACCESS_LOG=Trueasyncdefget_datetime():returndatetime.now().strftime("%Y-%m-%d%H:%M:%S")@app.route('/getdatetime')asyncdefgetdatetime(request):returnjson({"now":awaitget_datetime(),'server_name':request.server_name,'path':request.path})if__name__=="__main__":app.run(host=HOST,port=PORT,debug=False,auto_reload=True,workers=multiprocessing.cpu_count()//5)12345678910111213141516171819202122于生产环境启动运行:该程序创建了一个可以访问当前时间的接口,并且使用异步支持,程序处理速度会更快,还进行了一些全局配置:开启访问日志、开启自动重载、CPU工作数量为当前系统的1/5(CPU数量设置越多,并发处理速度越快)、将404页面以json格式返回等访问成功示例:访问失败示例:访问日志:FBV模式其意为“基于函数的视图”(Function-basedView),尽管从个人角度来说此模式可能不太利于后期开发,可读性也不太好,但还是需要学习一下的:fromquery_tagimportQueryq=Query()asyncdefrequest_parse(request):platform,chain,address='platform','chain','address'ifrequest.method=='POST':parameters=request.jsonplatform,chain,address=parameters['platform'],parameters['chain'],parameters['address']elifrequest.method=='GET':parameters=request.argsplatform,chain,address=parameters['platform'][0],parameters['chain'][0],parameters['address'][0]print(f'请求参数为{platform},{chain},{address}')returnplatform,chain,address@app.route('/tag',methods=['GET','POST'],version=1,version_prefix='/api/v')asyncdefmain(request):platform,chain,address=awaitrequest_parse(request)ifplatform=='labelcloud':ifchain=='eth':addr=q.query_etherscan(address=address)returnjson({'addr':addr})elifchain=='bsc':addr=q.query_bscscan(address=address)returnjson({'addr':addr})elifchain=='polygon':addr=q.query_polygonscan(address=address)returnjson({'addr':addr})else:json({'error':f'thischainnoexists,availablein[eth,bsc,polygon]'})elifplatform=='oklink':addr=q.query_oklink_com(chain=chain,address=address)returnjson({'addr':addr})else:returnjson({'error':f'thisplatformnoexists,availablein[labelcloud,oklink]'})1234567891011121314151617181920212223242526272829303132333435此处展示了一个简单的FBV例子,该接口允许GET及POST请求,并为其定义了接口版本,一个请求url如下:http://127.0.0.1:7777/api/v1/tag?platform=labelcloud&chain=eth&address=0x9B9DBA51F809dd0F9E2607C458f23C1BD35Ab01b1其实这些框架的语法都相差不大,而Sanic的一大优势就是支持异步,所以速度会快很多,并发请求量越大,其优势就越明显,掌握它,将成为你的进阶技能树!CBV模式其意为“基于类的视图”(Class-basedView),此种模式使得代码的可读性大大增强,不仅可以提高开发效率,还利于后期维护,特别是一个项目由多个团队成员协同开发时往往选择该模式,我们将上面的FBV模式代码变为CBV模式的代码:fromsanic.viewsimportHTTPMethodView#CBV模式classTagView(HTTPMethodView):asyncdefget(self,request):parameters=request.argsplatform,chain,address=parameters.get('platform',[''])[0],parameters.get('chain',[''])[0],parameters.get('address',[''])[0]ifplatform=='labelcloud':ifchain=='eth':addr=q.query_etherscan(address=address)returnjson({'addr':addr})elifchain=='bsc':addr=q.query_bscscan(address=address)returnjson({'addr':addr})elifchain=='polygon':addr=q.query_polygonscan(address=address)returnjson({'addr':addr})else:json({'error':f'thischainnoexists,availablein[eth,bsc,polygon]'})elifplatform=='oklink':addr=q.query_oklink_com(chain=chain,address=address)returnjson({'addr':addr})else:returnjson({'error':f'thisplatformisnoexists,availablein[labelcloud,oklink]'})asyncdefpost(self,request,name):pass#把类视图添加进路由app.add_route(TagView.as_view(),'/tag',version=1,version_prefix='/api/v')123456789101112131415161718192021222324252627282930类TagView继承了sanic中views模块的HTTPMethodView类,而类下面的方法即为对应请求类型的处理逻辑,最后用app的add_route()方法将该类作为视图添加进应用的路由中,代码已变得十分优雅!OpenAPI文档你还可以将你的接口变成一份精美的文档,使得其他人更方便的阅读及理解你的接口,你只需安装其所属的扩展工具:pipinstallsanic-ext-ihttps://pypi.doubanio.com/simple1接下来布局API文档:fromsanicimport(exceptions,Sanic,)fromsanic.viewsimportHTTPMethodViewfromsanic_extimport(openapi,Extend,)fromspiders.query_tagimportQueryapp=Sanic('TagAPI')Extend(app)classTagView(HTTPMethodView)openapi.definition(description='ThisAPIcangettagforlabelcloudoroklinkbyasynchronousrequest.',parameter=[{"name":"platform","in":"query","type":"string","description":"Platform(labelcloudoroklink)","default":"labelcloud"},{"name":"chain","in":"query","type":"string","description":"labelcloudincluding(eth,bsc,polygon),oklinkincluding(eth,bsc,polygon,tron,btc,avalanche,arbitrum,optimism)",'default':'eth'},{"name":"address","in":"query","type":"string","description":"Blockchainaddress",'default':'0xB72eD8401892466Ea8aF528C1af1d0524bc5e105'}])asyncdefget(self,request):q=Query()parameters=request.argsplatform,chain,address=parameters['platform'][0],parameters['chain'][0],parameters['address'][0]ifplatform=='labelcloud':ifchain=='eth':addr=q.query_etherscan(address=address)returnjson({'data':addr})elifchain=='bsc':addr=q.query_bscscan(address=address)returnjson({'data':addr})elifchain=='polygon':addr=q.query_polygonscan(address=address)returnjson({'data':addr})else:raiseexceptions.SanicException(message=f'thischainnoexists,availablein[eth,bsc,polygon]')elifplatform=='oklink':addr=q.query_oklink_com(chain=chain,address=address)returnjson({'data':addr})else:returnexceptions.SanicException(message=f'thisplatformisnoexists,availablein[labelcloud,oklink]')1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162从代码可看出,其API文档的设置是利用sanic-ext中的openapi和Extend模块,其中openapi采用装饰器的方式附加在请求类型方法上,我们定义了接口的描述和一些参数属性,包括网址参数名、参数类型、参数描述、参数默认值等打开网址http://127.0.0.0:7777/docs/redoc1你将看见默认的Redoc风格的API文档:打开网址http://127.0.0.0:7777/docs/swagger1你将看见Swagger风格的API文档:TortoiseORMORM(ObjectRelationalMapping),中文为“对象关系映射”,目的是为了集中数据模型和数据规则,确保安全地管理数据(提供对SQL注入的免疫力),还可以提高开发效率。而TortoiseORM是一个使用asyncio语法的ORM,其灵感来源于Django自带的ORM,所以它的语法和DjangoORM极其相似那么Sanic为啥要选择TortoiseORM作为最佳搭档呢?首先Tortoise本身就是使用asyncio语法的,与Sanic一样,其次它的API设计既干净又实用,性能上也比其他PythonORM要好:从上图来看,TortoiseORM在各方面的功能支持确实比较良好,目前支持的数据库有MySQL、SQLite、Oracle、PostgreSQL等安装TortoiseORM:pipinstalltortoise-orm1定义一个博客模型:fromtortoise.modelsimportModelfromtortoiseimportfieldsfromdatetimeimportdateclassBlog(Model):headline=fields.CharField(max_length=100)author=fields.CharField(max_length=20,default='makerchen66')pub_date=fields.DateField(default=date.today())content=fields.TextField()def__str__(self):returnself.headlineclassMeta:db_table='blog'123456789101112131415然后需要初始化模型和数据库:fromtortoiseimportTortoise,run_asyncasyncdefinit():awaitTortoise.init(db_url='sqlite://db.sqlite3',modules={'models':['app.models']})#GeneratetheschemaawaitTortoise.generate_schemas()run_async(init()1234567891011最后就可使用模型:#Createinstancebysaveblog=Blog(headline='震惊!某知名女明星竟然。。。',content='在一个风雨交加的夜晚,某国知名功夫宗师--马宝锅,正在练功室内锻炼绝技。。。',author='makerchen66',pub_date=date(2006,3,3))awaitblog.save()#Orby.create()awaitBlog.create(headline='震惊!某知名女明星竟然。。。',content='在一个风雨交加的夜晚,某国知名功夫宗师--马宝锅,正在练功室内锻炼绝技。。。',author='makerchen66',pub_date=date(2006,3,3))#NowsearchforarecordqueryResult=awaitBlog.filter(headline__contains='女明星').first()print(queryResult.author)12345678910更多TortoiseORM使用教程可参考官网:https://tortoise.github.io/#tutorial1TortoiseORMGithub项目地址:https://github.com/tortoise/tortoise-orm1接下来将爬虫项目和Sanic结合起来三、爬虫API实战项目接下来创建一个爬虫API实战项目,并且使路由模块、爬虫模块、视图模块、项目启动文件、配置文件独立由于代码量较大,以下只展示部分核心文件和代码,视图模块中的tag_views.py文件:爬虫模块中的query_tag.py文件:路由模块中的tag_routers.py文件:fromviews.tag_viewimportTagViewclassTagRouter:defload_router(self,app):app.add_route(TagView.as_view(),'/tag',version=1,version_prefix='/api/v')123456server.py文件:项目架构已搭建好,往后可以不断扩充新模块和功能四、服务器部署及接口性能测试使用screen工具挂载Sanic项目:screen-Ssanic_api1查看是否创建成功:screen-ls1进入项目:screen-d-rsanic_api1进入项目所在根目录,创建虚拟环境:virtualenvvenv--python=python3.9.171进入虚拟环境:sourcevenv/bin/activate1安装项目所需的Python环境:pipinstall-rrequirements.txt-ihttps://pypi.doubanio.com/simple1最后启动项目:pythonserver.py1启动成功:对接口进行测试,由于使用asyncio且CPU工作数量较多,故并发处理量较大,速度很快:http://服务器IP:7777/api/v1/tag?platform=labelcloud&chain=eth&address=0x9B9DBA51F809dd0F9E2607C458f23C1BD35Ab01b1若要退出该screen项目,使它挂载在后台,可以使用快捷键【Ctrl+a+d】删除该screen项目:screen-S-Xsanic_screen_idquit1如果对性能有更进一步的要求,可以和NginxDocker等结合部署。五、作者InfoAuthor:小鸿的摸鱼日常,Goal:让编程更有趣!专注于Web开发、爬虫,游戏开发,数据分析、自然语言处理,AI等,期待你的关注,让我们一起成长、一起Coding!版权说明:本文禁止抄袭、转载,侵权必究!
|
|