整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Gin(三):與模板配合使用 tmpl,go web 開發最火框架之一

          過Gin(二):路由Router ,go語言框架學習的學習,已經對 Gin 有了一個初步的認識和了解,對 router 的簡單使用也有了一定的掌握,那么今天就來使用 Gin 來渲染出我們的 html 頁面吧。

          添加模板

          我們仍舊是在上一章節的項目中進行修改。

          首先新建一個 templates 文件夾,用于存放我們的模板文件,在文件夾中新建立 index.tmpl。并且編寫我們的模板。

           <!doctype html>
           <html lang="en">
           <head>
           <meta charset="UTF-8">
           <meta name="viewport"
           content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
           <meta http-equiv="X-UA-Compatible" content="ie=edge">
           <title>Gin Hello</title>
           </head>
           <body>
           <main>{{ .title }}</main>
           </body>
           </html>
          

          小提示 GoLand 現在還未對 tmpl 有高亮顯示語法,我們可以將 .tmpl 后綴文件添加到 go Template 模板。方法如下:File-settings-Editor-File Types。(或者我們直接使用 *.gohtml 做為模板也是可以的)如圖:

          我們可以通過 LoadHTMLGlob 和 LoadHTMLFiles 兩個方法來對我們的模板進行加載。其中 LoadHTMLGlob 方法可以將一個目錄下所有的模板進行加載,而LoadHTMLFiles只會加載一個文件,他的參數為可變長參數,需要我們一個一個的手動將模板文件填寫。這里我們使用 LoadHTMLGlob 方法。

           router.LoadHTMLGlob("templates/*")
          

          此時我們需要修改我們的 / 路由了,不再是讓它返回一個字符串,而是返回我們的頁面模板。

          在 handler 中新建立一個 indexHandler.go ,用來處理我們的 / 路由。

           func Index(context *gin.Context) {
           context.HTML(http.StatusOK, "index.tmpl", gin.H{
           "title": "hello gin " + strings.ToLower(context.Request.Method) + " method",
           })
          }
          

          此時在訪問我們的頁面,仍舊是 hello gin get method,但是這和我們之前返回的字符串是不同的。

          打開 瀏覽器-Network 就可以看到這兩個頁面的不同,一個是 text 一個是 html

          寫完具體功能,我們需要改造一下我們的單元測試,針對新的接口邏輯原有的單元測試已經行不通了。

          重新修改單元測試。

           func TestIndexHtml(t *testing.T) {
           router := initRouter.SetupRouter()
           w := httptest.NewRecorder()
           req, _ := http.NewRequest(http.MethodGet, "/", nil)
           router.ServeHTTP(w, req)
           assert.Equal(t, http.StatusOK, w.Code)
          }
          

          進行單元測試的時候,發現報錯了,報錯原因是竟然是找不到 html。

           --- FAIL: TestIndexGetRouter (0.00s)
           panic: html/template: pattern matches no files: `templates/*` [recovered]
           panic: html/template: pattern matches no files: `templates/*`
          

          此時就感到很奇怪了,為什么網頁上可以很好的訪問到,在測試中卻無法訪問呢?

          查了很多資料沒有找到原因,很多解決方法是將 templates 寫成全路徑,這顯然不是很好的解決方法。官方對于單元測試介紹少的可憐。

          這里我介紹一種方法:

          我們需要修改方法,通過判斷不同的模式(debug,release,test)來加載不同路徑下的 templates。

          initRouter.go

           // 省略部分代碼 
           if mode := gin.Mode(); mode == gin.TestMode {
           router.LoadHTMLGlob("./../templates/*")
           } else {
           router.LoadHTMLGlob("templates/*")
          }
          

          同時,也需要修改 test,我們要寫個 init 方法,這里的 init 方法就好比 java 中 Junit 中的 @Before

           package test
           ?
           import (
           "GinHello/initRouter"
           "github.com/gin-gonic/gin"
           "github.com/stretchr/testify/assert"
           "net/http"
           "net/http/httptest"
           "testing"
           )
           ?
           var router *gin.Engine
           ?
           func init() {
           gin.SetMode(gin.TestMode)
           router = initRouter.SetupRouter()
           }
           ?
           func TestIndexHtml(t *testing.T) {
           w := httptest.NewRecorder()
           req, _ := http.NewRequest(http.MethodGet, "/", nil)
           router.ServeHTTP(w, req)
           assert.Equal(t, http.StatusOK, w.Code)
           assert.Contains(t,w.Body.String(),"hello gin get method","返回的HTML頁面中應該包含 hello gin get method")
           }
          

          這樣完善了單元測試,方便日后的功能更改。

          ?添加靜態資源

          當網頁可以正常顯示的時候,我們可以添加一些靜態資源來使我們的頁面更加美觀。我在這里選擇了 Bootstrap 4 做為一個 UI 界面框架。Bootstrap 4 下載

          同時還要引入 Jquery 和 Popper。

          我們新建一個 statics 文件夾,將我們 Bootstrap 解壓,將 js 和 css 復制到 statics 目錄下。

          在我們的 initRouter 中,對靜態資源進行添加。

           router.Static("/statics","./statics")
          

          新建 header.tmpl

           {{ define "header" }}
           <nav class="navbar navbar-expand-lg navbar-light bg-light">
           <a class="navbar-brand" href="#">Gin Hello</a>
           <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
           aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
           <span class="navbar-toggler-icon"></span>
           </button>
           ?
           <div class="collapse navbar-collapse" id="navbarSupportedContent">
           <ul class="navbar-nav mr-auto">
           <li class="nav-item active">
           <a class="nav-link" href="#">主頁 <span class="sr-only">(current)</span></a>
           </li>
           <li class="nav-item">
           <a class="nav-link" href="#">文章列表</a>
           </li>
           <li class="nav-item">
           <a class="nav-link " href="#" tabindex="-1" aria-disabled="true">關于</a>
           </li>
           </ul>
           <form class="form-inline my-2 my-lg-0">
           <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
           <button class="btn btn-outline-success my-2 my-sm-0" type="submit">搜索</button>
           </form>
           <ul class="navbar-nav ">
           <li class="nav-item">
           <a class="nav-link" href="#">登錄</a>
           </li>
           <li class="nav-item">
           <a class="nav-link" href="#">注冊</a>
           </li>
           </ul>
           </div>
           </nav>
           {{end}}
          

          并在我們的 index.tmpl 上進行添加

           <body>
           <header>
           {{template "header"}}
           </header>
           <main>
           {{ .title }}
           </main>
           </body>
          

          此時運行我們的網站,出現下圖樣式。

          添加網站圖標

          萬事俱備,只欠一個 icon。

          網站此時還缺少網站的圖標,網站圖標也是通過 Gin 給定的函數設置。我們將 .ico 圖片放到項目根目錄下,然后在 initRouter 中設置。

           router.StaticFile("/favicon.ico","./favicon.ico")
          

          再次運行我們的網站,此時就會發現網站的左上角標簽頁中出現了設置好的圖標。

          ?總結

          通過本章節的介紹和學習,可以很快的使用 Gin 中的靜態資源,定義網站圖標等。

          ?本章節代碼

          Github 點擊了解更多查看全部代碼

          推薦閱讀

          Gin(一):Hello Gin ,學習 Gin 從這里開始

          Gin(二):路由Router ,go語言框架學習

          Gin(三):與模板配合使用 tmpl,go web 開發最火框架之一

          Gin(四):接收表單數據和模型綁定,Go語言最火web框架之一

          Gin(五):連接MySQL , Go 輕量級框架 Gin

          Gin(六):文件的上傳,go語言最火框架之一

          Gin(七):中間件的介紹和使用,GO語言最火的框架之一

          Gin(八):cookies使用「不做標題黨,讓你看后有所收獲」

          Gin(九):生成restful 接口,go語言最火web框架之一

          Gin(十): 集成 Swagger,Gin配置這個神器,再也不用寫接口文檔了

          程和編碼概念

          使用docker一鍵啟動!

          docker run -d -e REDIS_HOST=192.168.200.150 cnaafhvk/proxy-factory product start
          

          如果你不喜歡用docker的話,那么請往下看。

          關注后私信小編 PDF領取十套電子文檔書籍

          安裝

          # python3 以上版本
          pip install proxy-factory
          # 依賴 redis(必須), tesseract-ocr(可選)
          

          運行

          product start
          

          1分鐘后看看你本地redis中good_proxies字段,是不是已經有了不少代理?

          超簡單有木有

          但是!

          理想很豐滿,現實很骨感。如果你運氣好一個坑都沒有踩到,那么請點右上角(或左上角)x,我們下次再見。但是我很清楚,99%的盆友都會遇到各種安裝坑,所以如何躲坑也是我下面即將講述的重點,支起耳朵來吧!

          首先

          程序使用到了redis做為存儲,如果你電腦上正好安裝有redis同時也啟動著,那么恭喜你,這個坑不會撂倒你。如果沒有,那么請安裝

          #ubutnu & pi
          apt-get install redis-server
          

          其它平臺請自行google。

          其次

          程序使用到了 tesseract-ocr 這個google開源的驗證碼識別程序,代理網站mimvp很坑爹,端口使用圖片,于是乎只能機器識別了。當然,不安裝ocr也沒有關系,無非放棄這個網站嘍。

          #ubutnu & pi
          apt-get install tesseract-ocr
          

          最后

          還是上面那個垃圾網站的坑,因為要識別驗證碼,我對圖片進行了處理,所以需要pillow,pillow的安裝請自行查看pillow官網,如果想放棄這個網站,打開我的源碼,把這個網站相關的代碼注釋掉即可。

          如果你是windows平臺,相信我,千萬坑總有一個能把你撂倒,珍愛生命,遠離windows。

          好了,坑講解完畢。

          下面講啟動方式。

          啟動方式

          程序雖小,功能挺全。

          先貼下指令

          usage: proxy factory [-h] [-s SETTINGS] [-cm CHECK_METHOD] [-sm SPIDER_MODULE]
           [-d]
           [{stop,start,restart,status}]
          positional arguments:
           {stop,start,restart,status}
          optional arguments:
           -h, --help show this help message and exit
           -s SETTINGS, --settings SETTINGS
           local settings.
           -cm CHECK_METHOD, --check-method CHECK_METHOD
           proivde a check method to check proxies.
           eg:module.func
           -sm SPIDER_MODULE, --spider-module SPIDER_MODULE
           proivde a module contains proxy site spider methods.
           eg:module
           -d, --daemon
          ####################################################################
          - product start: 程序開始(阻塞式)
          - product -d start: 程序開始(守護進程模式)
          - product restart 程序重啟(守護進程模式)
          - product stop 程序關閉(守護進程模式)
          - product status 程序狀態(守護進程模式)
          - product -s localsettings 指定一個自定義配置模塊。(只要在sys.path中就可以找到)
          - product -cm check-method 指定一個自定義檢查方法。(只要在sys.path中就可以找到)
          - product -sm spider-module 指定一個自定義的spider模塊,存放自定義的spider方法。(只要在sys.path中就可以找到)
          

          自定義檢查方法

          def check(self, proxy):
           """
           自義定檢查方法
           :param self: ProxyFactory對象
           :param proxy: 代理
           :return: True則代理可用,否則False
           """
           import requests
           resp = requests.get("http://2017.ip138.com/ic.asp", proxies={"http": "http://%s"%proxy})
           self.logger.info(resp.text)
           ....
           return resp.status_code < 300
          

          將檢查方法保存成python文件,比如check,然后-cm check.check指向他即可。

          自定義代理網站

          def fetch_custom(self, page=5):
           """
           自定義代理網站抓取
           :param self:ProxyFactory對象
           :param page: 可以在里記錄一些可選參數,但是方法只能接收一個必選參數
           :return: set類型的代理列表,ip:port
           """
           proxies = set()
           url_tmpl = "http://www.kxdaili.com/dailiip/1/%d.html"
           for page_num in range(page):
           url = url_tmpl % (page_num + 1)
           soup = BeautifulSoup(get_html(url, self.headers), "html")
           table_tag = soup.find("table", attrs={"class": "segment"})
           trs = table_tag.tbody.find_all("tr")
           for tr in trs:
           tds = tr.find_all("td")
           ip = tds[0].text
           port = tds[1].text
           latency = tds[4].text.split(" ")[0]
           if float(latency) < 0.5: # 輸出延遲小于0.5秒的代理
           proxy = "%s:%s" % (ip, port)
           proxies.add(proxy)
           return proxies
          

          將代理網站方法保存成python文件,比如proxy_sites.py 然后-sm proxy_site指向他即可。

          配置模塊

          REDIS_HOST = "0.0.0.0"
          REDIS_PORT = 6379
          # 質量不好的代理檢查的時間間隔
          BAD_CHECK_INTERVAL = 60
          # 質量不好的代理連續檢查失敗次數的最大值,超過則丟棄
          FAILED_TIMES = 5
          # 質量好的代理檢查的時間間隔
          GOOD_CHECK_INTERVAL = 60
          # 抓取新代理的時間間隔
          FETCH_INTERVAL = 60
          LOG_LEVEL = 'DEBUG'
          LOG_MAX_BYTES = 1024*1024*10
          LOG_BACKUPS = 5
          LOG_DIR = "/home/pi/logs"
          LOG_STDOUT = False
          LOG_JSON = False 
          

          將配置模塊信息保存成localsettings.py,然后-s 指向他就可以。同時,程序還支持環境變量配置,只要將字段保存為環境變量信息,如 export GOOD_CHECK_INTERVAL = 120,配置即可生效,優先級關系:環境變量>localsettings>defaultsettings。

          redis中的狀態

          127.0.0.1:6379> keys *
          1) "good_proxies"
          2) "bad_proxies"
          127.0.0.1:6379> type good_proxies
          set
          127.0.0.1:6379> type bad_proxies
          hash
          127.0.0.1:6379> smembers good_proxies
           1) "110.77.227.20:51552"
           2) "46.8.243.89:65205"
           3) "118.193.107.175:80"
           4) "223.99.214.21:53281"
           5) "119.41.200.20:53281"
           6) "120.198.224.7:8080"
           7) "110.77.177.116:51552"
           8) "36.37.219.198:53281"
           9) "138.197.230.116:55555"
          10) "219.138.58.59:3128"
          11) "192.158.236.58:3128"
          12) "58.26.10.67:8080"
          13) "60.208.44.228:80"
          14) "120.198.224.5:8080"
          15) "103.231.218.126:53281"
          16) "186.215.148.228:80"
          17) "210.26.125.142:8080"
          18) "31.145.111.12:65103"
          19) "218.201.98.196:3128"
          20) "61.160.208.222:8080"
          21) "101.200.45.131:3128"
          22) "120.198.224.6:8080"
          23) "52.66.155.0:80"
          24) "195.234.87.211:53281"
          25) "192.117.146.110:80"
          26) "106.14.51.145:8118"
          27) "106.75.25.3:80"
          28) "177.24.31.129:8080"
          29) "203.153.113.226:51552"
          30) "118.193.107.222:80"
          31) "112.13.93.43:8088"
          32) "114.215.103.121:8081"
          33) "118.193.107.240:80"
          34) "111.56.5.41:80"
          35) "118.193.107.138:80"
          36) "118.193.107.182:80"
          37) "183.215.140.117:8118"
          38) "110.77.227.35:51552"
          39) "137.74.254.242:3128"
          40) "110.77.239.184:51552"
          41) "94.177.201.18:80"
          42) "110.77.210.182:51552"
          43) "202.51.188.170:53281"
          44) "124.133.230.254:80"
          45) "120.198.224.5:8088"
          46) "118.193.107.180:80"
          47) "121.69.45.162:8118"
          48) "118.193.107.100:80"
          127.0.0.1:6379> 
          

          9個代理網站,有反爬機制的只有2個,一個是mimvp,使用圖片端口反爬,一個是goubanjia,使用js混淆反爬,有興趣的可以研究一下。

          我一直在使用一個小工具,并發現它在構建Javascript應用過程中非常實用。它是一個非常簡單的模板函數,速度快,支持緩存,并容易使用。我想分享一下使用它的過程中的一些技巧。

            以下是模板函數的代碼(你可以從正要出版的Secrets of the JavaScript Ninja一書中得到更精煉的版本):

          // 簡單JavaScript模板引擎
          // John Resig – http://ejohn.org/ – MIT Licensed
          (function(){
          var cache = {};
          this.tmpl = function tmpl(str, data){
          // 判斷我們是否已經有這么一個模板,或者我們需要載入模板
          // 并保證把結果保存到緩存中。
          var fn = !/W/.test(str) ?
          cache[str] = cache[str] ||
          tmpl(document.getElementById(str).innerHTML) :

          // 生成一個可重用的函數,用于提供模板生成功能
          // (它會被記錄到緩存內).
          new Function(“obj”,
          “var p=[],print=function(){p.push.apply(p,arguments);};” +

          // 通過with(){}把數據作為本地變量引入
          “with(obj){p.push(‘” +

          // 把模板轉換未純javascript代碼
          str
          .replace(/[rtn]/g, ” “)
          .split(“<%”).join(“t”)
          .replace(/((^|%>)[^t]*)’/g, “r”)
          .replace(/t=(.*?)%>/g, “‘,,'”)
          .split(“t”).join(“‘);”)
          .split(“%>”).join(“p.push(‘”)
          .split(“r”).join(“\'”)
          + “‘);}return p.join(”);”);

          // 給用戶提供一些基本的柯里化功能
          return data ? fn( data ) : fn;
          };
          })();

            你的模板代碼看起來將是類似于(這并不是規定的格式,但是我比較喜歡這樣):

          <script type=”text/html” id=”item_tmpl”>
          <div id=”<%=id%>” class=”<%=(i % 2 == 1 ? ” even” : “”)%>”>
          <div class=”grid_1 alpha right”>
          <img class=”righted” src=”<%=profile_image_url%>”/>
          </div>
          <div class=”grid_6 omega contents”>
          <p><b><a href=”/<%=from_user%>”><%=from_user%></a>:</b> <%=text%></p>
          </div>
          </div>
          </script>

            你也可以內嵌腳本:

          <script type=”text/html” id=”user_tmpl”>
          <% for ( var i = 0; i < users.length; i++ ) { %>
          <li><a href=”<%=users[i].url%>”><%=users[i].name%></a></li>
          <% } %>
          </script>

            提示:把腳本內嵌到你的頁面中,并且content-type是未知的(例如在這個例子中,瀏覽器不知道該如何執行 text/html 腳本),那么瀏覽器會把它忽略掉 – 同時搜索引擎和屏幕讀取也會忽略掉它。這是一個非常好的偽裝代碼,可以把你的模板嵌入到你的頁面中。我喜歡使用快速卻又隨性的技術,我只需一到兩個小模板,就可以得到又輕型和快速應用。你可以在腳本中,像這樣去使用:

          var results = document.getElementById(“results”);
          results.innerHTML = tmpl(“item_tmpl”, dataObject);

            你可以預編譯結果,在稍后使用。如果你只使用一個ID作為參數(或者一個模板代碼)來調用模板函數,那么它就會返回一個預編譯的函數,你就可以在稍后調用:

          var show_user = tmpl(“item_tmpl”), html = “”;
          for ( var i = 0; i < users.length; i++ ) {
          html += show_user( users[i] );
          }

            這是目前最沒辦法的辦法,解析和轉換代碼——對這你很可能無愛。不過他只有我中意的一項技術:在字符串中用字符靜態搜索和靜態替換時,比如split(“match”).join(“replace”),執行速度更好——看起來不直觀但可以有效工作在現代瀏覽器里(下一版FireFox會大幅提高replace(/match/g,”replace”)的性能——所以現在這樣的長表達式以后不需要的)。

            放輕松享受它——我很好奇代碼中的突變。即使它很簡單,仍然有很多事情可以用它做。


          主站蜘蛛池模板: 无码人妻一区二区三区在线视频| 亚洲国产激情一区二区三区| 精品人妻一区二区三区四区 | 一区二区三区在线观看视频| 亚洲av午夜福利精品一区人妖| 午夜无码一区二区三区在线观看 | 亚洲国产成人精品久久久国产成人一区二区三区综 | 日韩精品午夜视频一区二区三区| 蜜桃无码一区二区三区| 国产午夜精品一区二区三区小说| 国产在线一区二区三区在线| 亚洲综合无码一区二区痴汉| 91大神在线精品视频一区| 国产一区二区三区不卡观| 丰满人妻一区二区三区免费视频| 国产三级一区二区三区| 国产婷婷色一区二区三区深爱网| 国产欧美色一区二区三区| 国产精品一区视频| 亚洲区精品久久一区二区三区| 亚洲国产精品自在线一区二区 | 无码人妻精品一区二区在线视频| 国偷自产Av一区二区三区吞精 | 天美传媒一区二区三区| 午夜性色一区二区三区不卡视频| 精品久久久久久无码中文字幕一区 | 精品一区二区三区在线观看视频| 无码国产精品一区二区免费16| 国产一区二区精品久久| 久久精品亚洲一区二区三区浴池| 激情内射亚洲一区二区三区爱妻 | 精品久久综合一区二区| 八戒久久精品一区二区三区| 亚洲成人一区二区| 精品亚洲综合在线第一区| 亚洲综合一区二区| 日韩精品一区二区三区在线观看l| 免费国产在线精品一区| 中文字幕一区二区免费| 一区二区三区日韩精品| 性色av无码免费一区二区三区 |