【Python實戰】跟我一步一步來,用Tornado來實現你的服務器夢想,純乾貨教學,有彩蛋

看完此文章,你將能夠獨立完成:html

  • 在服務器上能夠寫一個簡單的靜態網頁,並訪問
  • 能夠爲你的App寫接口,提供Json格式的數據
  • 服務器定時執行某項任務


上一篇經過訪問公衆號獲取每日最新資訊的文章一出『這一次,他經過公衆號訪問最新的1024資訊信息』,真的是沒想到,你們的熱情一下那麼高,致使個人服務器壓力很大。讓我真的是很意外,仍是要感謝你們的支持。上回答應過你們,要給你們說一下須要怎樣作,纔可以實現那樣的功能。因此,這回我主要講一下,如何用Tornado來搭建你本身的服務器。WeRoBot微信自動回覆機器人下一期再說吧。前端

我敢打包票,85%的人看不完這篇文章。你們的自覺性就是這樣。java

授人以魚不如授人以漁,這就是我爲何要寫這些文章的原因。今天既然可以經過公衆號來訪問到小草,那麼明天我就能夠經過公衆號上訪問天天新聞的最新消息,或者我關注的人的微博更新,或者美劇是否又跟新了,或者視頻網站是否又出新視頻了,或者一些論壇是否發了最新的帖子,甚至天天早晨一塊兒來,均可以經過本身的算法再結合昨天的股票數據,來推測今天大盤的漲跌,這些東西背後的原理其實都差很少的。因此,不要把本身的思路侷限在一點,要擴散,要放開,這樣纔會有騷操做的出現。python

行了,廢話不閒扯了,來開始說說咱們今天的主角:Tornado吧。web

啥是Tornado

Tornado就是龍捲風,哦不,這裏說的Tornado是一種 Web 服務器軟件的開源版本。Tornado 和如今的主流 Web 服務器框架(包括大多數 Python 的框架)有着明顯的區別:它是非阻塞式服務器,並且速度至關快。算法

Tornado須要用Python編寫,因此,這一系列下來,咱們都是用的Python來搞事情,就和我以前說的,Python這個語言,最適合搞事情了!mongodb

這裏要說一點,Web框架有不少種,不一樣語言有不一樣的框架,並且特色都不同,就Ptyhon而言,用Python開發的Web框架也有好幾種,Django,Flask,Tornado,這些框架,也是各有各的特色。因此,我想說的是,至於要用那種框架,請結合你自身的需求來選擇。不要盲目的抓起一個隨便用,這樣未來會坑了本身。咱們這裏,就是小型服務,自娛自樂用,因此,沒有那麼多顧慮,隨便抓起來一個用就OK,這不,我抓的就Tornado。數據庫

把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: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爬蟲一步一步部署到騰訊雲上

這麼硬貨的公衆號,大家不關注一下啊?

相關文章
相關標籤/搜索