看完此文章,你將能夠獨立完成:html
- 在服務器上能夠寫一個簡單的靜態網頁,並訪問
- 能夠爲你的App寫接口,提供Json格式的數據
- 服務器定時執行某項任務
上一篇經過訪問公衆號獲取每日最新資訊的文章一出『這一次,他經過公衆號訪問最新的1024資訊信息』,真的是沒想到,你們的熱情一下那麼高,致使個人服務器壓力很大。讓我真的是很意外,仍是要感謝你們的支持。上回答應過你們,要給你們說一下須要怎樣作,纔可以實現那樣的功能。因此,這回我主要講一下,如何用Tornado來搭建你本身的服務器。WeRoBot微信自動回覆機器人下一期再說吧。前端
我敢打包票,85%的人看不完這篇文章。你們的自覺性就是這樣。java
授人以魚不如授人以漁,這就是我爲何要寫這些文章的原因。今天既然可以經過公衆號來訪問到小草,那麼明天我就能夠經過公衆號上訪問天天新聞的最新消息,或者我關注的人的微博更新,或者美劇是否又跟新了,或者視頻網站是否又出新視頻了,或者一些論壇是否發了最新的帖子,甚至天天早晨一塊兒來,均可以經過本身的算法再結合昨天的股票數據,來推測今天大盤的漲跌,這些東西背後的原理其實都差很少的。因此,不要把本身的思路侷限在一點,要擴散,要放開,這樣纔會有騷操做的出現。python
行了,廢話不閒扯了,來開始說說咱們今天的主角:Tornado吧。web
Tornado就是龍捲風,哦不,這裏說的Tornado是一種 Web 服務器軟件的開源版本。Tornado 和如今的主流 Web 服務器框架(包括大多數 Python 的框架)有着明顯的區別:它是非阻塞式服務器,並且速度至關快。算法
Tornado須要用Python編寫,因此,這一系列下來,咱們都是用的Python來搞事情,就和我以前說的,Python這個語言,最適合搞事情了!mongodb
這裏要說一點,Web框架有不少種,不一樣語言有不一樣的框架,並且特色都不同,就Ptyhon而言,用Python開發的Web框架也有好幾種,Django,Flask,Tornado,這些框架,也是各有各的特色。因此,我想說的是,至於要用那種框架,請結合你自身的需求來選擇。不要盲目的抓起一個隨便用,這樣未來會坑了本身。咱們這裏,就是小型服務,自娛自樂用,因此,沒有那麼多顧慮,隨便抓起來一個用就OK,這不,我抓的就Tornado。數據庫
首先,服務器或者你本地的機器上面,應該是有Python的,推薦Python3,而後,你的機器應該是有pip的。json
咱們須要經過pip來安裝Tornado後端
1# pip install tornado
複製代碼
安裝完成,若是想測試是否安裝功,只須要進入Python,而後輸入import tornado,若是沒有報錯,就說明安裝成功。
接着,咱們來搞一下本地的配置。
本地,我推薦使用PyCharm來作IDE。這個IDE功能還算能夠,若是你已經有本身習慣的IDE,能夠略過此處。
PyCharm官網上有兩個可下載的版本:
推薦下載第一個,Professional,這個版本功能很強大,並且支持不少Web框架的插件。
可是好多人會發現,這個是收費版本的啊,那怎麼用?
別急,破解方法很是簡單,第一次打開PyCharm的時候,選擇License server激活,而後填入:http://im.js.cn:8888
或 http://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()
複製代碼
在這個裏面,最關鍵的,有這麼幾個地方:
OK,上面簡單的分析,就是Tornado處理一個網絡請求的邏輯。捋順這個邏輯以後,咱們接下來就開始簡單的編寫一下咱們本身的服務端代碼吧。
明確一下咱們的兩個目的:
好的,下面咱們就起來擼代碼,不對,是擼起來代碼。
遵循咱們上面所說的,定義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.py
和web_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部分。
咱們要在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返回結果,咱們這裏就用到了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頁面,只須要在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爬蟲一步一步部署到騰訊雲上
這麼硬貨的公衆號,大家不關注一下啊?