1. 程式人生 > >go語言帶cookie的net客戶端請求與[]byte轉string

go語言帶cookie的net客戶端請求與[]byte轉string

前些日子參加了一個叫Advent of Code的程式設計大賽,每天一道題,快活似神仙。這每道題都有自己的拼圖資料輸入puzzle input,要做題就需要用到該資料,把資料複製過來感覺又太麻煩,於是就興起寫了一個直接從html讀取資料的函式。
資料如下:

+12
-10
-4
-8
+18
-1
-13
...

檢視標準庫文件,發現net/html包可以做這個功能,其函式如下:

resp, err := http.Get("http://example.com/")
if err != nil {
    // handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
// ...

然後除錯,但並未有相關資料輸出,在瀏覽器中檢查元素發現該請求需要帶cookie才能正確返回資料。直接使用http.Get()並不帶有cookie,所以改用NewRequest使用指定的方法、網址和可選的主題建立並返回一個新的*Request。其函式如下:

client := &http.Client{}
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        log.Fatal(err)
    }
    req.Header.Set("Cookie", "name=value")
    resp, err := client.Do(req)

    robots, err := ioutil.ReadAll(resp.Body)


  resp.Body.Close()//必須要關閉Body

ioutil.ReadAll()返回的是[]byte型別,入需要使用可以先將[]byte轉換成string,Go語言初學者都會的型別轉換語法:string(b),Go為了穩定性對於上述方法需要經過一些資料上的複製,一旦資料量過大,這個成本是難以忍受的。
所以為了讓Go服帖,我們得用上unsafe包,unsafe包提供一些可以跳過Go語言型別安全限制的操作。看下面程式碼:
go func BytesString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) }
我們取到[]byte的指標,Go會說*byte不是*string

,但是我們有外掛unsafe.Pointer,所以Go就通過了,接著你很自在的把*byte轉成了*string,因為reflect.StringHeaderreflect.SliceHeader的結構體只相差末尾一個欄位。
類似的用法可以看Go語言黑魔法
接著用regexp包正則表示式FindAllString取出匹配的[]string資料使用,然後再用strconv.Atoi()進行轉化就可以了。
Day1的題為求和,其程式碼如下:

package main
import (
   "fmt"
   "io/ioutil"
   "log"
   "net/http"
   "os"
   "regexp"
   "strconv"
   "unsafe"
)
func BytesString(b []byte) string {//[]byte 轉string
   return *(*string)(unsafe.Pointer(&b))
}
func getPuzzle(url string) string {//從網頁抓取資料
   client := &http.Client{}
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
       log.Fatal(err)
   }
   req.Header.Set("Cookie", "session=53616c7xxx")
   resp, err := client.Do(req)
   robots, err := ioutil.ReadAll(resp.Body)
   resp.Body.Close()
   str := BytesString(robots)
   return str
}
func sum(num []int) int {
   sum := 0
   for _, n := range num {
       sum += n
   }
   return sum
}
func strtoint(str []string) []int {//string轉int
   num := make([]int, len(str))
   for i := 0; i < len(str); i++ {
       flag := str[i][0]
       chafre, _ := strconv.Atoi(str[i][1:])
       switch flag {
       case '+':
           num[i] = chafre
       case '-':
           num[i] = -chafre
       }
   }
   return num
}
func main() {
   change := getPuzzle("https://adventofcode.com/2018/day/1/input")
   re := regexp.MustCompile("[+|-][0-9]*")//正則表示式
   str := re.FindAllString(change, -1)
   num := strtoint(str)
   sum := sum(num)
   fmt.Printf("sum is %d\n", sum)
}

如果有更好的方法,歡迎私信,哈哈哈···