爬蟲前端頁面展示
前端頁面展示架構
鏈接Elasticsearch
1.在docker里運行elasticsearch docker run -id -p 9200:9200 elasticsearch
2.下載elastic庫。https://github.com/olivere/elastic
,選擇相應的版本(本項目5.0版本),獲取軟件包go get gopkg.in/olivere/elastic.v5
3.如果您的Elasticsearch服務器在不同的IP和/或端口上運行,只需提供一個指向NewClient的URL:
// Create a client and connect to http://192.168.2.10:9201
client, err := elastic.NewClient(elastic.SetURL("http://192.168.2.10:9201"))
if err != nil {
// Handle error
}
但我們的elasticsearch運行在docker容器里,所以我們要從新指定地址:
// sniff 會請求http://ip:port/_nodes/http,將其返回的url list作為新的url list。
// 如果snifferEnabled被設置為false,那么則不啟動該功能。
client, err := elastic.NewClient(
elastic.SetSniff(false),
elastic.SetURL("http://192.168.200.17:9200"))
if err != nil {
return nil, err
}
將數據存儲到Elasticsearch
func save(client *elastic.Client, index string, item engine.Item) error {
if item.Type == "" {
return errors.New("must supply Type")
}
indexService := client.Index(). //鏈接數據庫
Index(index). //相當於MySQL里的數據庫
Type(item.Type).//相當於MySQL里的表
BodyJson(item) //把數據轉為json格式
if item.Id != "" {
indexService.Id(item.Id)
}
_, err := indexService.Do(context.Background())
if err != nil {
return err
}
return nil
}
這里我們定義了一個函數來調用。傳進來三個參數,client index item。
client: 是我們在外面創建好的鏈接elastic的客戶端。
index: 是外面用戶要鏈接elastic哪個索引(相當於MySQL的數據庫)
item: 存儲的數據
注意:
type Item struct { //參數item的類型
Id string
Type string
Url string
Payload interface{}
}
標准模板庫template(前端頁面)
基本語法
1.變量
模板內內嵌的語法支持,全部需要加{{}}來標記。
在模板文件內, . 代表了當前變量,即在非循環體內,.就代表了傳入的那個變量。假設我們定義了一個結構體:
type Article struct {
ArticleId int
ArticleContent string
}
那么我們在模板內可以通過
<p>{{.ArticleContent}}<span>{{.ArticleId}}</span></p>
來獲取並把變量的內容渲染到模板內。假設上述的結構體的內容為ArticleId:1 ArticleContent:”hello”, 則對應渲染后的模板內容為:
<p>hello<span>1</span></p>
當然,我們有時候需要定義變量,比如我們需要定義一個article變量,同時將其初始化為”hello”,那么我們可以這樣寫:
{{$article := "hello"}}
假設我們想要把傳入值的內容賦值給article,則可以這樣寫:
{{$article := .ArticleContent}}
2.判斷
golang的模板也支持if的條件判斷,當前支持最簡單的bool類型和字符串類型的判斷
{{if .condition}}
{{end}}
當.condition為bool類型的時候,則為true表示執行,當.condition為string類型的時候,則非空表示執行。
當然也支持else , else if嵌套
{{if .condition1}}
{{else if .contition2}}
{{end}}
假設我們需要邏輯判斷,比如與或、大小不等於等判斷的時候,我們需要一些內置的模板函數來做這些工作,目前常用的一些內置模板函數有:
not 非
{{if not .condition}}
{{end}}
and 與
{{if and .condition1 .condition2}}
{{end}}
or 或
{{if or .condition1 .condition2}}
{{end}}
eq 等於
{{if eq .var1 .var2}}
{{end}}
ne 不等於
{{if ne .var1 .var2}}
{{end}}
lt 小於 (less than)
{{if lt .var1 .var2}}
{{end}}
le 小於等於
{{if le .var1 .var2}}
{{end}}
gt 大於
{{if gt .var1 .var2}}
{{end}}
ge 大於等於
{{if ge .var1 .var2}}
{{end}}
3.循環
golang的template支持range循環來遍歷map、slice內的內容,語法為:
{{range $i, $v := .slice}}
{{end}}
在這個range循環內,我們可以通過iv來訪問遍歷的值,還有一種遍歷方式為:
{{range .slice}}
{{end}}
這種方式無法訪問到index或者key的值,需要通過.來訪問對應的value
{{range .slice}}
{{.field}}
{{end}}
當然這里使用了.來訪問遍歷的值,那么我們想要在其中訪問外部的變量怎么辦?(比如渲染模板傳入的變量),在這里,我們需要使用$.來訪問外部的變量
{{range .slice}}
{{$.ArticleContent}}
{{end}}
實現前端展示
elastic查詢語法
//取所有
res, err = client.Search("megacorp").Type("employee").Do(context.Background())
printEmployee(res, err)
//字段相等
q := elastic.NewQueryStringQuery("last_name:Smith")
res, err = client.Search("megacorp").Type("employee").Query(q).Do(context.Background())
if err != nil {
println(err.Error())
}
//條件查詢
//年齡大於30歲的
boolQ := elastic.NewBoolQuery()
boolQ.Must(elastic.NewMatchQuery("last_name", "smith"))
boolQ.Filter(elastic.NewRangeQuery("age").Gt(30))
res, err = client.Search("megacorp").Type("employee").Query(q).Do(context.Background())
printEmployee(res, err)
//短語搜索 搜索about字段中有 rock climbing
matchPhraseQuery := elastic.NewMatchPhraseQuery("about", "rock climbing")
res, err = client.Search("megacorp").Type("employee").Query(matchPhraseQuery).Do(context.Background())
printEmployee(res, err)
在本項目中我的搜索沒有弄的那么強大:
func (h SearchResultHandler) getSearchResult(q string, from int) (model.SearchResult, error) {
var result model.SearchResult
resp, err := h.client.Search("zhenai_date").
Query(elastic.NewQueryStringQuery(rewriteQueryString(q))). //根據關鍵值去每個字段進行模糊查詢
From(from).
Do(context.Background())
if err != nil {
return result, err
}
result.Query = q
result.Hits = resp.TotalHits()
result.Start = from
result.Items = resp.Each(reflect.TypeOf(engine.Item{}))
result.PrevFrom = result.Start - len(result.Items) //分頁
result.NextFrom = result.Start + len(result.Items)
return result, nil
}
//把關鍵值重寫
func rewriteQueryString(q string) string {
re := regexp.MustCompile(`([A-z][a-z]*):`)
return re.ReplaceAllString(q, "Payload.$1:")
}
前端頁面展示
前端頁面可以實現簡單的查詢和分頁。
總結
到此爬蟲的並發版和前端的展示完成。完整代碼:
https://github.com/cwyfengyiyuan/golang-crawler.git