社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

【Python实战】跟我一步一步来,用Tornado来实现你的服务器梦想,纯干货教学,有彩蛋

皮克啪的铲屎官 • 7 年前 • 724 次点击  

【Python实战】跟我一步一步来,用Tornado来实现你的服务器梦想,纯干货教学,有彩蛋

看完此文章,你将可以独立完成:

  • 在服务器上可以写一个简单的静态网页,并访问
  • 可以为你的App写接口,提供Json格式的数据
  • 服务器定时执行某项任务


上一篇通过访问公众号获取每日最新资讯的文章一出『这一次,他通过公众号访问最新的1024资讯信息』,真的是没想到,大家的热情一下那么高,导致我的服务器压力很大。让我真的是很意外,还是要感谢大家的支持。上回答应过大家,要给大家说一下需要怎样做,才能够实现那样的功能。所以,这回我主要讲一下,如何用Tornado来搭建你自己的服务器。WeRoBot微信自动回复机器人下一期再说吧。

我敢打包票,85%的人看不完这篇文章。大家的自觉性就是这样。

授人以鱼不如授人以渔,这就是我为什么要写这些文章的缘由。今天既然能够通过公众号来访问到小草,那么明天我就可以通过公众号上访问每天新闻的最新消息,或者我关注的人的微博更新,或者美剧是否又跟新了,或者视频网站是否又出新视频了,或者一些论坛是否发了最新的帖子,甚至每天早晨一起来,都可以通过自己的算法再结合昨天的股票数据,来推测今天大盘的涨跌,这些东西背后的原理其实都差不多的。所以,不要把自己的思路局限在一点,要扩散,要放开,这样才会有骚操作的出现。

行了,废话不闲扯了,来开始说说我们今天的主角:Tornado吧。

啥是Tornado

Tornado就是龙卷风,哦不,这里说的Tornado是一种 Web 服务器软件的开源版本。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。

Tornado需要用Python编写,所以,这一系列下来,我们都是用的Python来搞事情,就和我之前说的,Python这个语言,最适合搞事情了!

这里要说一点,Web框架有很多种,不同语言有不同的框架,而且特点都不一样,就Ptyhon而言,用Python开发的Web框架也有好几种,Django,Flask,Tornado,这些框架,也是各有各的特点。所以,我想说的是,至于要用那种框架,请结合你自身的需求来选择。不要盲目的抓起一个随便用,这样将来会坑了自己。我们这里,就是小型服务,自娱自乐用,所以,没有那么多顾虑,随便抓起来一个用就OK,这不,我抓的就Tornado。

把Tornado搞到服务器上

首先,服务器或者你本地的机器上面,应该是有Python的,推荐Python3,然后,你的机器应该是有pip的。

我们需要通过pip来安装Tornado

1# pip install tornado

安装完成,如果想测试是否安装功,只需要进入Python,然后输入import tornado,如果没有报错,就说明安装成功。

接着,我们来搞一下本地的配置。

本地,我推荐使用PyCharm来做IDE。这个IDE功能还算可以,如果你已经有自己习惯的IDE,可以略过此处。

PyCharm官网上有两个可下载的版本:


推荐下载第一个,Professional,这个版本功能很强大,而且支持很多Web框架的插件。

但是好多人会发现,这个是收费版本的啊,那怎么用?

别急,破解方法非常简单,第一次打开PyCharm的时候,选择License server激活,然后填入:http://im.js.cn:8888http://idea.java.sx/http://xidea.online,然后点Activate激活即可。

接着,我们需要将本地的代码和服务端的代码要同步起来,做好映射,设置的步骤也很简单。这里,我们假设远端的服务器地址是39.11.12.123

Tools -> Deployment -> Configuration里面:


点击左上角的 + 号:


出来的对话框里,名字随便写,但是下面的要选择SFTP


接着,下面这张图,第一个红框里面填写远程服务器的ip地址:39.11.12.123,第二个填写你服务器上的登录账户名称,一般是root,第三个就是密码。


接着第二页,Mapping里面,第二个红框里面,填写你本机的工程目录地址,第三个红框填写在服务器上的工程目录地址(提前建好)。


然后点击OK。接着,在Tools -> Deployment -> Automatic Upload点击打钩,这样每次编写完一个文件,代码就可以自动同步到服务器上了。


每次如果需要同步的话,可以在Tools -> Deployment菜单里面,选择Upload to XXXX就行,或者在需要上传的文件图标点击右键,在Deployment里面选择就可以。很方便。上传成功的样子大概就是这样:


好了,我们接下来就要尝试着编写我们的代码了。但是,对于第一次接触新框架的你,我们还是先看一下Tornad的“Hello World”怎么写吧。

 1import tornado.ioloop
 2import tornado.web
 3
 4class MainHandler(tornado.web.RequestHandler):
 5    def get(self):     # 3
 6        self.write("Hello, world")     # 4
 7
 8def make_app():
 9    return


    
 tornado.web.Application([
10        (r"/", MainHandler),     # 2
11    ])
12
13if __name__ == "__main__":
14    app = make_app()     # 1
15    app.listen(8888)
16    tornado.ioloop.IOLoop.current().start()

在这个里面,最关键的,有这么几个地方:

  1. make_app()声明一个tornado的application,里面就规定了服务器接收处理的url路径。
  2. 服务器接收了url,将会把请求交给MainHandler()来做处理。
  3. MainHandler中的get方法,是用来处理HTTP GET请求的。
  4. 返回结果,只返回了一个字符串。

OK,上面简单的分析,就是Tornado处理一个网络请求的逻辑。捋顺这个逻辑之后,我们接下来就开始简单的编写一下我们自己的服务端代码吧。

撸码时刻

明确一下我们的两个目的:

  • 我们的网站能够访问数据库并且显示在网页上
  • 我们的网站能够做到给App提供数据接口功能,返回Json格式的数据。

好的,下面我们就起来撸代码,不对,是撸起来代码。

遵循我们上面所说的,定义url路径,然后写Handler。所以,我就先按照这个思路,把工程目录按照这个样子建立了一下:


然后,我们在main.py这个文件里面编写代码如下:

 1class Application(tornado.web.Application):
 2    def __init__(self):
 3        handlers = [
 4            (r"/web/", WebHandle),
 5            (r"/json/", JsonHandle),
 6        ]
 7        # 定义tornado服务器的配置项,如static/templates目录位置,debug级别等
 8        settings = dict(
 9            debug=True,
10            static_path=os.path.join(os.path.dirname(__file__), "static"),
11            template_path=os.path.join(os.path.dirname(__file__), "templates")
12        )
13        tornado.web.Application.__init__(self, handlers, **settings)
14
15
16if __name__ == "__main__":
17    print("Tornado server is ready for service\r")
18    Application().listen(8000, xheaders=True)
19    tornado.ioloop.IOLoop.current().start()

这里简单做一下解释:
我们定义两个Handler,一个是返回网页版本的Handler,另一个是返回Json版本的;我们的Application的写法也和Hellow world例子中写的不一样,我们这样写,可以自定义很多设置,比如路径,是否Debug模式之类的。
那么我们接下来看看连个Handler怎么写的:

1# views.json
2class JsonHandle(tornado.web.RequestHandler):
3    def get(self, *args, **kwargs):
4        self.write("json view")
5
6# views.web
7class WebHandle(tornado.web.RequestHandler):
8    def get(self, *args, **kwargs):
9        self.write("web view")

这里是两个及其简单的实现,我们来看一下效果:



下面这个是访问错误的url出现的页面,因为我们开了Debug模式,所以页面长这个样子:


404页面的问题我们之后会说到。

到这里位置,我们有一个地方不知道大家发现没有,十分的不灵活,就是上面url匹配的地方。这里指定了:http://xxxxxx/json/只能用JsonHandler来处理,但是如果来了http://xxxxxx/json/XX,他就会报错,页面未找到。处理这样的请求,让我们的服务变得更加强大,更加健壮,我们决定,新加一个url_router,在一定程度上,用它来控制我们的url匹配。

 1"""
 2    url_router.py
 3"""
 4def include(module):
 5    res = import_module(module)
 6    urls = getattr(res, 'urls', res)
 7    return urls
 8
 9
10def url_wrapper(urls):
11    wrapper_list = []
12    for url in urls:
13        path, handles = url
14        if isinstance(handles, (tuple, list)):
15            for handle in handles:
16                pattern, handle_class = handle
17                wrap = ('{0}{1}'.format(path, pattern), handle_class)
18                wrapper_list.append(wrap)
19        else:
20            wrapper_list.append((path, handles))
21    return wrapper_list

有了router,我们的main文件和handler文件都应该修改一下,在views.json和views.web目录下,分别建立json_urls.pyweb_urls.py

 1"""
 2    main.py
 3"""
 4class Application(tornado.web.Application):
 5    def __init__(self):
 6        # >>>> 不一样的地方开始
 7        handlers = url_wrapper([
 8            (r"/json/", include('views.json.json_urls')),
 9            (r"/web/", include('views.web.web_urls')),
10        ])
11        # 不一样的地方结束 <<<<
12        # 定义tornado服务器的配置项,如static/templates目录位置,debug级别等
13
14"""
15    json_urls.py
16"""        
17urls=[
18    (r'', JsonHandle)
19]
20
21"""
22    web_urls.py
23"""
24urls = [
25    (r"", WebHandle)
26]

这样写,虽然看上去比较乱一些,但是相当灵活。能够使我们的url变得丰富。比如,如果我想添加一个查看全部json文件的url,那么我只需要在json_urls里面,添加一个(r'/all', GetAllHandler)即可,然后在json_view.py里面实现GetAllHandler就可以了。这样做完,我们的服务器就可以同时处理http://xxxxxx/json/http://xxxxxx/json/all两个url了,而且是不同的handler处理。

此时此刻,我们大概的框架基本搭建完成。下面就来主要实现一下handler里面的功能吧。

因为我们要实现的是从数据库里面读取了数据在显示到网页上,所以,这里我们用到了PyMongo这个库。这个库是Python专门用来操作MongoDB的,炒鸡简单好用。

我们先来完成Json部分。

Json格式的返回实现

我们要在JsonHandler中,实现get()方法。这里,我们首先从数据库中读取出来数据,然后,得将数据转换成dict()格式,因为PyMongo读取出来的数据,不能够直接转成Json,因为里面有个叫Object_id的东西,所以,这里我们就手动转一下。然后,把数据用self.write(json.dumps({"data": {"block": return_data, "curTime": cur_time}}))的形式返回回去就好。结构相当简单,大致代码如下:

 1class JsonHandle(tornado.web.RequestHandler):
 2    def get(self):
 3        # 从数据库中读取数据
 4        self.client = pymongo.MongoClient("mongodb://39.11.12.123/", 27017)
 5        self.db = self.client["DailyProject"]
 6        self.table = self.db["table"]
 7        result = self.table.find()
 8        # 得到当前时间
 9        time = datetime.datetime.now()
10        cur_time = str(time.year) + "-" + str(time.month) + "-" + str(time.day)
11        # 筛选出合适的数据
12        temp_posts = []
13        posts = []
14        for item in result:
15            temp_posts.append(item)
16            temp_posts.sort(key=lambda k: (k['post_time'][-5:]), reverse=True)
17        for item in temp_posts:
18            if item['post_day_time'] == cur_time:
19                posts.append(item)
20        # 将数据转换成dict()类型,方便转换成Json
21        return_data = []
22        for item in posts:
23            temp_dic = {'postId': item['post_id'], 'postTitle': item['post_title'],
24                        'postPartUrl': item['post_part_url']}
25            return_data.append(temp_dic)
26        # 返回Json格式的数据
27        self.write(json.dumps({"data": {"block": return_data, "curTime": cur_tim

下面是效果:



这样,实现起来是不是超级酷。这里是实现了get方法,你也可以实现post方法来处理HTTP POST请求。具体的逻辑还是要根据你具体的业务来编写。反正最后用json.dumps返回就可以了。

小技巧:如果你返回的json格式都差不多,可以抽离出来,写一个模板,以后返回结果直接将数据传给模板就好。不需要在每个方法都写一遍json的格式,那样如果修改起来,会很费事儿。

Web格式的返回实现

Web返回结果,我们这里就用到了html的东西。首先,我们得在template里面建一个index.html文件。然后,在WebHandler中,最后返回结果写成:self.render("index.html", info=posts, today=cur_time)这样就可以了。这里简单说一下,第一个参数,是你template里面对应的html文件。第二个参数和第三个参数,是你需要传给前端的数据。名字随便叫,但是要和html里面保持一致。

Handler的代码大致如下:

 1class WebHandle(tornado.web.RequestHandler):
 2    def get(self):
 3        self.client = pymongo.MongoClient("mongodb://39.11.12.123/", 27017)
 4        self.db = self.client["DailyProject"]
 5        self.table = self.db["table"]
 6        result = self.table.find()
 7        time = datetime.datetime.now()
 8        cur_time = str(time.year) + "-" + str(time.month) + "-" + str(time.day)
 9        temp_posts = []
10        posts = []
11        for item in result:
12            temp_posts.append(item)
13            temp_posts.sort(key=lambda k: (k['post_time'][-5:]), reverse=True)
14        for item in temp_posts:
15            if item['post_day_time'] == cur_time:
16                posts.append(item)
17        self.render("index.html", info=posts, today=cur_time)

由于名字要和前端一一对应,所以,前端的代码如下:

 1<body>
 2
 3<h1>技术讨论  {{today}}</h1>
 4
 5{% for element in info %}
 6<div class="post_block">
 7
 8   <p class="post_id">{{element['post_id']}}</p>
 9      <a class="post_url" href="{{element['post_url']}}" data-url="{{element['post_url']}}" target="_blank">{{element['post_title']}}</a>
10   <p class="post_time">{{element['post_time']}}</p>
11
12</div>
13{% end %}
14
15</body>

注意,后端传过来的today对应的html里面的{{today}},info则对应的for循环里面的info。这种for循环,语法有点像DoT.js。别慌,这种前端的写法就那么几种,并不是很难,看懂例子怎么写,就照猫画虎的往自己的html里面写就可以。

看到了吗,就是这么简单,最后我们运行起来,效果如下:


404页面的处理

处理404页面,只需要在main.py文件的url中,加入一个(r".*", BaseHandle),然后在BaseHandler里面,返回一个你已经写好的404.html就好了。炒鸡简单。

最后很关键的,怎么跑起来程序!

最后,代码写好了,我们需要把我们的程序跑起来。

首先,将你的工程部署到你的服务器上,通过前文所讲的部署方法,成功传上去文件。

然后,登录到你的服务器,进入工程指定的文件夹。

由于我们的启动程序是在main.py里面写的,所以,这里只需要输入指令:

1# sudo python main.py &

就可以让你的Tornado后台运行了!千万别忘了后面还有个&

如果要关闭你的运行程序,则需要输入:

1# ps -ef | grep main.py

来查找你Tornado所在的进程,通过kill指令关闭就可。

1# kill -9 <进程号>

后记不后记

看到没有,这样就可以了。一个例子虽然很简单,但是这里可以扩展的地方有很多。很多同学肯定苦恼于不知道该怎么写服务端的代码,那么这篇文章所讲的东西可以很好的带你入门,并且入门还前进了一小步,因为并不是简简单单的只给你写hello world。

前面还提到了可以用Tornado来定时执行任务,这个东西我就不再这里说了,如果想更多交流的话,请关注『皮克啪的铲屎官』,点击下方的『进群交流』,来一起在群里讨论。

这些所讲的内容的代码,我也给大家共享出来,同样是关注『皮克啪的铲屎官』,回复『tornado』,即可获得下载地址。

最后给大家吐槽一句,爬虫的文章,你们看一篇就够了,因为爬虫这个东西,真的不是啥真金白银的技术活,这个东西,根本体现不出来你的技术,说白了就是个工具。没啥技术含量。那些爬来爬去爬美女爬帅哥的文章代码,我估计你写了运行一遍就完事儿了,根本不会再次运行它。因为它给你爬的数据没用啊。根本不像我之前的爬虫,我的爬虫,我把思路给大家讲好,而且,我的爬虫是实实在在的在服务端运行的。爬虫就是为提供数据,并不是什么高深的技术,而且工作岗位,爬虫都是现成的,根本轮不到你写。

推荐阅读

【Python实战】手把手超详细教程教你Scrapy爬达盖尔社区,有彩蛋
【Python实战】用Scrapy编写“1024网站种子吞噬爬虫”,送福利
【Python实战】用代码来访问1024网站,送福利
【Python实战】用Scrapyd把Scrapy爬虫一步一步部署到腾讯云上

这么硬货的公众号,你们不关注一下啊?




今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/c2QTjDxR3S
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/13394
 
724 次点击