跟我一步一步來用【Tornado】來實現你的【真正的】服務器夢想,純乾貨教學

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

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

開工大吉了,還不趕忙用六十四卦搖一搖啊?看看新年財運如何~html

由於文章都是涉及到服務器的,因此福利就要寫在最前面
過大年了,你們是否是又有了壓歲錢了啊??啊哈哈哈哈,壓歲錢買糖吃還不如投資到本身身上。好比用來買課程,或者用來買服務器,來學習編程,寫爬蟲。來買服務器啊買服務器啊!只在本地跑,根本沒用的!恰巧,鏟屎官這裏就有上千元的阿里雲和騰訊雲的優惠券給你使用(每一款優惠只要點擊優惠連接,進入便可領取):前端

阿里雲部分
【阿里雲新人1888元雲產品通用代金券】:
promotion.aliyun.com/ntms/yunpar…java

【阿里雲爆款雲主機,2折優惠券】:
promotion.aliyun.com/ntms/act/qw…python

【阿里雲企業級服務器2折優惠券】:
promotion.aliyun.com/ntms/act/en…web

騰訊雲算法

【新客戶無門檻領取總價值高達2775元代金券,每種代金券限量500張,先到先得】:
cloud.tencent.com/redirect.ph…mongodb

【騰訊雲服務器、雲數據庫特惠,3折優惠券】:
cloud.tencent.com/redirect.ph…數據庫

--接下來是正文--編程

今天鏟屎官給你們帶來的是,如何用Tornado來搭建你本身的服務器。

我敢打包票,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

# pip install tornado
複製代碼

安裝完成,若是想測試是否安裝功,只須要進入Python,而後輸入import tornado,若是沒有報錯,就說明安裝成功。

接着,咱們來搞一下本地的配置。

本地,我推薦使用PyCharm來作IDE。這個IDE功能還算能夠,若是你已經有本身習慣的IDE,能夠略過此處。

PyCharm官網上有兩個可下載的版本:

PyCharm官網的兩個版本
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裏面:

Tools -> Deployment -> Configuration
Tools -> Deployment -> Configuration

點擊左上角的 + 號:

"+"號
"+"號

出來的對話框裏,名字隨便寫,可是下面的要選擇SFTP

填寫SFTP
填寫SFTP

接着,下面這張圖,第一個紅框裏面填寫遠程服務器的ip地址:39.11.12.123,第二個填寫你服務器上的登陸帳戶名稱,通常是root,第三個就是密碼。

Deployment
Deployment

接着第二頁,Mapping裏面,第二個紅框裏面,填寫你本機的工程目錄地址,第三個紅框填寫在服務器上的工程目錄地址(提早建好)。

Mappings
Mappings

而後點擊OK。接着,在Tools -> Deployment -> Automatic Upload點擊打鉤,這樣每次編寫完一個文件,代碼就能夠自動同步到服務器上了。

Automatic Upload
Automatic Upload

每次若是須要同步的話,能夠在Tools -> Deployment菜單裏面,選擇Upload to XXXX就行,或者在須要上傳的文件圖標點擊右鍵,在Deployment裏面選擇就能夠。很方便。上傳成功的樣子大概就是這樣:

上傳成功
上傳成功

好了,咱們接下來就要嘗試着編寫咱們的代碼了。可是,對於第一次接觸新框架的你,咱們仍是先看一下Tornad的「Hello World」怎麼寫吧。

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):     # 3
        self.write("Hello, world")     # 4

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),     # 2
    ])

if __name__ == "__main__":
    app = make_app()     # 1
    app.listen(8888)
    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這個文件裏面編寫代碼以下:

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/web/", WebHandle),
            (r"/json/", JsonHandle),
        ]
        # 定義tornado服務器的配置項,如static/templates目錄位置,debug級別等
        settings = dict(
            debug=True,
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            template_path=os.path.join(os.path.dirname(__file__), "templates")
        )
        tornado.web.Application.__init__(self, handlers, **settings)


if __name__ == "__main__":
    print("Tornado server is ready for service\r")
    Application().listen(8000, xheaders=True)
    tornado.ioloop.IOLoop.current().start()
複製代碼

這裏簡單作一下解釋:
咱們定義兩個Handler,一個是返回網頁版本的Handler,另外一個是返回Json版本的;咱們的Application的寫法也和Hellow world例子中寫的不同,咱們這樣寫,能夠自定義不少設置,好比路徑,是否Debug模式之類的。
那麼咱們接下來看看連個Handler怎麼寫的:

# views.json
class JsonHandle(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        self.write("json view")

# views.web
class WebHandle(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        self.write("web view")
複製代碼

這裏是兩個及其簡單的實現,咱們來看一下效果:

JSON
JSON
Web
Web

下面這個是訪問錯誤的url出現的頁面,由於咱們開了Debug模式,因此頁面長這個樣子:

404
404

404頁面的問題咱們以後會說到。

到這裏位置,咱們有一個地方不知道你們發現沒有,十分的不靈活,就是上面url匹配的地方。這裏指定了:http://xxxxxx/json/只能用JsonHandler來處理,可是若是來了http://xxxxxx/json/XX,他就會報錯,頁面未找到。處理這樣的請求,讓咱們的服務變得更增強大,更加健壯,咱們決定,新加一個url_router,在必定程度上,用它來控制咱們的url匹配。

""" url_router.py """
def include(module):
    res = import_module(module)
    urls = getattr(res, 'urls', res)
    return urls


def url_wrapper(urls):
    wrapper_list = []
    for url in urls:
        path, handles = url
        if isinstance(handles, (tuple, list)):
            for handle in handles:
                pattern, handle_class = handle
                wrap = ('{0}{1}'.format(path, pattern), handle_class)
                wrapper_list.append(wrap)
        else:
            wrapper_list.append((path, handles))
    return wrapper_list
複製代碼

有了router,咱們的main文件和handler文件都應該修改一下,在views.json和views.web目錄下,分別創建json_urls.pyweb_urls.py

""" main.py """
class Application(tornado.web.Application):
    def __init__(self):
        # >>>> 不同的地方開始
        handlers = url_wrapper([
            (r"/json/", include('views.json.json_urls')),
            (r"/web/", include('views.web.web_urls')),
        ])
        # 不同的地方結束 <<<<
        # 定義tornado服務器的配置項,如static/templates目錄位置,debug級別等

""" json_urls.py """        
urls=[
    (r'', JsonHandle)
]

""" web_urls.py """
urls = [
    (r"", WebHandle)
]
複製代碼

這樣寫,雖然看上去比較亂一些,可是至關靈活。可以使咱們的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}}))的形式返回回去就好。結構至關簡單,大體代碼以下:

class JsonHandle(tornado.web.RequestHandler):
    def get(self):
        # 從數據庫中讀取數據
        self.client = pymongo.MongoClient("mongodb://39.11.12.123/", 27017)
        self.db = self.client["DailyProject"]
        self.table = self.db["table"]
        result = self.table.find()
        # 獲得當前時間
        time = datetime.datetime.now()
        cur_time = str(time.year) + "-" + str(time.month) + "-" + str(time.day)
        # 篩選出合適的數據
        temp_posts = []
        posts = []
        for item in result:
            temp_posts.append(item)
            temp_posts.sort(key=lambda k: (k['post_time'][-5:]), reverse=True)
        for item in temp_posts:
            if item['post_day_time'] == cur_time:
                posts.append(item)
        # 將數據轉換成dict()類型,方便轉換成Json
        return_data = []
        for item in posts:
            temp_dic = {'postId': item['post_id'], 'postTitle': item['post_title'],
                        'postPartUrl': item['post_part_url']}
            return_data.append(temp_dic)
        # 返回Json格式的數據
        self.write(json.dumps({"data": {"block": return_data, "curTime": cur_tim
複製代碼

下面是效果:

JSON
JSON
JSON
JSON

這樣,實現起來是否是超級酷。這裏是實現了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的代碼大體以下:

class WebHandle(tornado.web.RequestHandler):
    def get(self):
        self.client = pymongo.MongoClient("mongodb://39.11.12.123/", 27017)
        self.db = self.client["DailyProject"]
        self.table = self.db["table"]
        result = self.table.find()
        time = datetime.datetime.now()
        cur_time = str(time.year) + "-" + str(time.month) + "-" + str(time.day)
        temp_posts = []
        posts = []
        for item in result:
            temp_posts.append(item)
            temp_posts.sort(key=lambda k: (k['post_time'][-5:]), reverse=True)
        for item in temp_posts:
            if item['post_day_time'] == cur_time:
                posts.append(item)
        self.render("index.html", info=posts, today=cur_time)
複製代碼

因爲名字要和前端一一對應,因此,前端的代碼以下:

<body>

<h1>技術討論  {{today}}</h1>

{% for element in info %}
<div class="post_block">

   <p class="post_id">{{element['post_id']}}</p>
      <a class="post_url" href="{{element['post_url']}}" data-url="{{element['post_url']}}" target="_blank">{{element['post_title']}}</a>
   <p class="post_time">{{element['post_time']}}</p>

</div>
{% end %}

</body>
複製代碼

注意,後端傳過來的today對應的html裏面的{{today}},info則對應的for循環裏面的info。這種for循環,語法有點像DoT.js。別慌,這種前端的寫法就那麼幾種,並非很難,看懂例子怎麼寫,就照貓畫虎的往本身的html裏面寫就能夠。

看到了嗎,就是這麼簡單,最後咱們運行起來,效果以下:

Web
Web

404頁面的處理

處理404頁面,只須要在main.py文件的url中,加入一個(r".*", BaseHandle),而後在BaseHandler裏面,返回一個你已經寫好的404.html就行了。炒雞簡單。

最後很關鍵的,怎麼跑起來程序!

最後,代碼寫好了,咱們須要把咱們的程序跑起來。

首先,將你的工程部署到你的服務器上,經過前文所講的部署方法,成功傳上去文件。

而後,登陸到你的服務器,進入工程指定的文件夾。

因爲咱們的啓動程序是在main.py裏面寫的,因此,這裏只須要輸入指令:

# sudo python main.py &
複製代碼

就可讓你的Tornado後臺運行了!千萬別忘了後面還有個&

若是要關閉你的運行程序,則須要輸入:

# ps -ef | grep main.py
複製代碼

來查找你Tornado所在的進程,經過kill指令關閉就可。

# kill -9 <進程號>
複製代碼

後記不是後記

看到沒有,這樣就能夠了。一個例子雖然很簡單,可是這裏能夠擴展的地方有不少。不少同窗確定苦惱於不知道該怎麼寫服務端的代碼,那麼這篇文章所講的東西能夠很好的帶你入門,而且入門還前進了一小步,由於並非簡簡單單的只給你寫hello world。

前面還提到了能夠用Tornado來定時執行任務,這個東西我就再也不這裏說了,若是想更多交流的話,請關注『皮爺擼碼』,點擊下方的『進羣交流』,來一塊兒在羣裏討論。

這些所講的內容的代碼,我也給你們共享出來,一樣是關注『皮爺擼嗎』,回覆『代碼』,便可得到下載地址。

最後給你們吐槽一句,爬蟲的文章,大家看一篇就夠了,由於爬蟲這個東西,真的不是啥真金白銀的技術活,這個東西,根本體現不出來你的技術,說白了就是個工具。沒啥技術含量。那些爬來爬去爬美女爬帥哥的文章代碼,我估計你寫了運行一遍就完事兒了,根本不會再次運行它。由於它給你爬的數據沒用啊。根本不像我以前的爬蟲,個人爬蟲,我把思路給你們講好,並且,個人爬蟲是實實在在的在服務端運行的。 爬蟲就是爲提供數據,並非什麼高深的技術,並且工做崗位,爬蟲都是現成的,根本輪不到你寫。

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

相關文章
相關標籤/搜索