Go抓取網頁數據並存入MySQL和返回json數據<四>

上一節已將將須要的數據從網站http://www.gratisography.com/ 抓取並存入數據庫【使用crawldata.go中的InsertData(&imageDatas)函數】,如今須要將數據從數據庫indiepic的表gratisography中取出並然會json格式的數據。git

項目文件夾結構以下:github

indiepic
├── README.md
├── crawldata
│   ├── crawldata.go
│   └── database.go
└── indiepic.go

如今將獲取數據的函數寫在database.go中:web

func GetAllImages() (imageDatas ImageDatas, err error) {
    // 鏈接數據庫
    db, err := OpenDatabase()
    if err != nil {
        fmt.Printf(s.Join([]string{"鏈接數據庫失敗", err.Error()}, "-->"))
        return nil, err
    }
    defer db.Close()

    // Prepare statement for inserting data
    imgOut, err := db.Query("SELECT * FROM gratisography")
    if err != nil {
        fmt.Println(s.Join([]string{"獲取數據失敗", err.Error()}, "-->"))
        return nil, err
    }
    defer imgOut.Close()

    // 定義掃描select到的數據庫字段的變量
    var (
        id          int
        img_url     string
        type_name   string
        title       string
        width       int
        height      int
        create_time string
    )
    for imgOut.Next() {
        // db.Query()中select幾個字段就須要Scan多少個字段
        err := imgOut.Scan(&id, &img_url, &type_name, &title, &width, &height, &create_time)
        if err != nil {
            fmt.Println(s.Join([]string{"查詢數據失敗", err.Error()}, "-->"))
            return nil, err
        } else {
            imageData := ImageData{img_url, type_name, title, width, height}
            imageDatas = append(imageDatas, imageData)
        }
    }

    return imageDatas, nil
}

值得一提的是在SELECT語句中拿到多少個字段就須要在Scan的時候使用變量去獲取多少個字段,否測會報錯。因此建議不要像上面那樣SELECT *,而是指定須要的字段如SELECT id,img_url,title FROM tableName
GetAllImages()函數返回兩個參數imageDatas ImageDataserr error數據庫

雖然使用GO本身寫一個HTTP請求很簡單,但爲了更好地處理路由和數據,這裏使用一個web框架martini Classy web framework for Go。
在使用以前須要先獲取:json

go get github.com/go-martini/martini

indiepic.go中引入martini:api

import (
    "github.com/go-martini/martini"
)

定義一個結構體Results用於表示輸出結果的數據結構:瀏覽器

type Results struct {
    Err   int                  // 錯誤碼
    Msg   string               // 錯誤信息
    Datas crawldata.ImageDatas // 數據,無數據時爲nil
}

由於須要輸出json格式數據,因此須要用martiniencoder中間件資源,使用下面命令獲取:數據結構

go get github.com/martini-contrib/encoder

而後import:app

import (
    "github.com/martini-contrib/encoder"
)

由於數據已經抓取完存入數據庫了,因此在main函數中,就不在須要調用crawldata.Crawl()了,將其註釋掉。而後編寫以下代碼:框架

func main() {
    // 使用crawldata包裏面的Crawl()抓取須要的數據存到數據庫
    // crawldata.Crawl()

    m := martini.New()
    route := martini.NewRouter()

    var (
        results Results
        err     error
    )

    m.Use(func(c martini.Context, w http.ResponseWriter, r *http.Request) {
        // 將encoder.JsonEncoder{}按照encoder.Encoder接口(注意大小寫)類型注入到內部
        c.MapTo(encoder.JsonEncoder{}, (*encoder.Encoder)(nil))
        w.Header().Set("Content-Type", "application/json; charset=utf-8")
    })

    route.Get("/", func(enc encoder.Encoder) (int, []byte) {
        result := Results{10001, "Not Found Data", nil}
        return http.StatusOK, encoder.Must(enc.Encode(result))
    })

    route.Get("/api", func(enc encoder.Encoder) (int, []byte) {
        results.Datas, err = crawldata.GetAllImages()
        if err != nil {
            fmt.Println(s.Join([]string{"獲取數據失敗", err.Error()}, "-->"))
            result := Results{10001, "Data Error", nil}
            return http.StatusOK, encoder.Must(enc.Encode(result))
        } else {
            results.Err = 10001
            results.Msg = "獲取數據成功"
            return http.StatusOK, encoder.Must(enc.Encode(results))
        }
    })

    m.Action(route.Handle)
    m.Run()
}

import部分:

import (
    "fmt"
    "github.com/go-martini/martini"
    "github.com/martini-contrib/encoder"
    "indiepic/crawldata"
    "net/http"
    s "strings"
)

而後運行:

go run indiepic.go

在瀏覽器中訪問 http://127.0.0.1:3000/api 便可看到輸出的json數據。若是安裝了postman能夠使用postman訪問地址,查看時選擇json

到這裏這個例子就結束了。源碼見GitHub

相關文章
相關標籤/搜索