簡單動手寫個小程式:使用http去抓取MOTC Transport API V2 公車資訊,再使用json套件解析出資訊會列印出來。
1.先新增個可以爬蟲首頁的簡單code,裡面使用到了http套件去抓google首頁的資料,然後把response資料印出來
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
var (
resp *http.Response
err error
body []byte
)
client := &http.Client{}
url := "https://www.google.com/?hl=zh_tw"
reqest, err := http.NewRequest("GET", url, nil)
if err != nil {
panic(err)
}
resp, _ = client.Do(reqest)
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("ioutil.ReadAll error:", err)
return
}
fmt.Println(string(body))
}
執行後應該可以順利取得google首頁的html資料
2.使用go module
go mod init
裡面空無一物
module internal/test3
go 1.14
2.原本是取google首頁,改打odata api
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
var (
resp *http.Response
err error
body []byte
)
client := &http.Client{}
url := "https://ptx.transportdata.tw/MOTC/v2/Bus/RealTimeByFrequency/City/Taipei?$top=30&$format=JSON"
reqest, err := http.NewRequest("GET", url, nil)
//增加header
reqest.Header.Add("Accept", "application/json")
reqest.Header.Add("Authorization", `hmac username="FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF", algorithm="hmac-sha1", headers="x-date", signature="o68jC/8QXQxWz9QW6uut0VxJKCQ="`)
reqest.Header.Add("x-date", `Mon, 21 Sep 2020 05:56:45 GMT`)
if err != nil {
panic(err)
}
resp, _ = client.Do(reqest)
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("ioutil.ReadAll error:", err)
return
}
fmt.Println(string(body))
}
執行成功後應該會回傳json,例如下面的資料
[{"PlateNumb":"049-FV","OperatorID":"18","RouteUID":"HSZ0007","RouteID":"0007","RouteName":{"Zh_tw":"81","En":"81"},"SubRouteUID":"HSZ000701","SubRouteID":"000701","SubRouteName":{"Zh_tw":"81","En":"81"},"Direction":0,"BusPosition":{"PositionLat":24.7699483333333,"PositionLon":120.988136666667,"GeoHash":"wsqhcjhz7"},"Speed":0.0,"Azimuth":0.0,"DutyStatus":0,"BusStatus":0,"MessageType":1,"GPSTime":"2020-09-21T13:59:33+08:00","SrcRecTime":"2020-09-21T13:59:32+08:00","SrcTransTime":"2020-09-21T13:59:32+08:00","UpdateTime":"2020-09-21T13:59:35+08:00"},{"PlateNumb":"097-FN","OperatorID":"13","RouteUID":"HSZ0010","RouteID":"0010","RouteName":{"Zh_tw":"藍線1區","En":"藍線1區"},"SubRouteUID":"HSZ001001","SubRouteID":"001001","SubRouteName":{"Zh_tw":"藍線1區","En":"藍線1區"},"Direction":0,"BusPosition":{"PositionLat":24.7882566666667,"PositionLon":121.008413333333,"GeoHash":"wsqj18edh"},"Speed":5.0,"Azimuth":133.0,"DutyStatus":0,"BusStatus":0,"MessageType":1,"GPSTime":"2020-09-21T13:59:36+08:00","SrcRecTime":"2020-09-21T13:59:36+08:00","SrcTransTime":"2020-09-21T13:59:36+08:00","UpdateTime":"2020-09-21T13:59:40+08:00"},{"PlateNumb":"099-FN","OperatorID":"13","RouteUID":"HSZ0743","RouteID":"0743","RouteName":{"Zh_tw":"藍線","En":"藍線"},"SubRouteUID":"HSZ074302","SubRouteID":"074302","SubRouteName":{"Zh_tw":"藍線","En":"藍線"},"Direction":1,"BusPosition":{"PositionLat":24.7541816666667,"PositionLon":121.73931,"GeoHash":"wsqsf4rge"}...
3.因為回傳值為json,就來用個套件gjson來解析
go get github.com/tidwall/gjson
這時候go.mod就會新增了一筆套件
require github.com/tidwall/gjson v1.6.1
把gjson套件複製到project的vendor底下
go mod vendor
這時候就可以在程式裡面import gjson套件來解析json,這次的目標是取得RouteName底下的Zh_tw的值
package main
import (
"fmt"
"io/ioutil"
"net/http"
gjson "github.com/tidwall/gjson"
)
func main() {
var (
resp *http.Response
err error
body []byte
)
client := &http.Client{}
url := "https://ptx.transportdata.tw/MOTC/v2/Bus/RealTimeByFrequency/City/Taipei?$top=30&$format=JSON"
reqest, err := http.NewRequest("GET", url, nil)
//增加header选项
reqest.Header.Add("Accept", "application/json")
reqest.Header.Add("Authorization", `hmac username="FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF", algorithm="hmac-sha1", headers="x-date", signature="9wk7knxmeIOECQIBAoHUatzFwUY="`)
reqest.Header.Add("x-date", `Mon, 21 Sep 2020 06:51:37 GMT`)
if err != nil {
panic(err)
}
//处理返回结果
resp, _ = client.Do(reqest)
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("ioutil.ReadAll error:", err)
return
}
//把body透過gjson.ParseBytes轉成gjson.Result的型態,因為回傳值是slice,所以用他的function Array()轉成[]gjson.Result
gg := gjson.ParseBytes(body).Array()
//使用for range遍歷整個slice,並印出資料
for _, g := range gg {
fmt.Println("g:", g)
zhtw := getRouteName(g)
fmt.Println("zhtw:", zhtw)
}
}
func getRouteName(g gjson.Result) string {
zhtw := g.Get("RouteName.Zh_tw").String()
return zhtw
}
執行結果
g: {"PlateNumb":"009-U5","OperatorID":"200","RouteUID":"TPE16111","RouteID":"16111","RouteName":{"Zh_tw":"307","En":"307"},"SubRouteUID":"TPE157462","SubRouteID":"157462","SubRouteName":{"Zh_tw":"307莒光往板橋前站","En":"307"},"Direction":1,"BusPosition":{"PositionLat":25.051583,"PositionLon":121.558462,"GeoHash":"wsqqw0s0j"},"Speed":0.0,"Azimuth":267.0,"DutyStatus":1,"BusStatus":0,"MessageType":0,"GPSTime":"2020-09-21T14:54:00+08:00","SrcUpdateTime":"2020-09-21T14:54:00+08:00","UpdateTime":"2020-09-21T14:54:01+08:00"}
zhtw: 307
是不是很簡單阿~~~