go語言帶cookie的net客戶端請求與[]byte轉string
阿新 • • 發佈:2018-12-04
前些日子參加了一個叫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.StringHeader
和reflect.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)
}
如果有更好的方法,歡迎私信,哈哈哈···