package main
import (
"fmt"
"log"
"net/http"
"os"
"golang.org/x/net/html"
)
var (
str string = "https://docs.hacknode.org/gopl-zh/"
)
//CreatFile is a func ti make infomation in file
func CreatFile(bt []byte) {
f, err := os.OpenFile("F:/MyGo/src/practice/url.txt", os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer f.Close()
res, err := f.Write([]byte(bt))
if err != nil {
log.Fatal(err)
}
if res == 0 {
fmt.Println("no one")
}
}
//GetURLInfomation is a func get URL infomation
func GetURLInfomation(URL string) []string {
resp, err := http.Get(URL)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {//判斷狀態
log.Fatal("Can't connect")
}
//開始節點處理
doc, err := html.Parse(resp.Body)
if err != nil {
log.Fatal(err)
}
var links []string
ForOneNode := func(n *html.Node) {
//匿名函數,單次節點處理,為什麼使用匿名函數,在下面講解
if n.Type == html.ElementNode && n.Data == "a" {//判斷是否為節點,節點為<a>標籤
for _, a := range n.Attr {//遍曆標籤屬性
if a.Key != "href" {
continue
}
link, err := resp.Request.URL.Parse(a.Val)//解析出URL地址,即屬性內容
if err != nil {
log.Fatal(err)
}
links = append(links, link.String())
}
}
}
ForEachNode(doc, ForOneNode, nil)//遍曆開始
return links
}
//ForEachNode is 廣度優先遍曆
func ForEachNode(n *html.Node, pre, post func(n *html.Node)) {
if pre != nil {
pre(n)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
ForEachNode(c, pre, post)
}
if post != nil {
post(n)
}
}
func main() {
bt := GetURLInfomation("https://docs.hacknode.org/gopl-zh/")
for _, t := range bt {
t += "\n"
CreatFile([]byte(t))
}
//CreatFile(bt)
}
註:為什麼使用匿名函數
1.在函數體內,需要將取到的值進行保留,如果使用return函數返回,函數內還要使用到*http.respone類型的變數,在遞迴調用的時候,參數會很繁雜
2.如果使用了上述情況,在廣度優先遍曆的時候,內部使用遞迴調用,在接收傳回值的時候,會很麻煩,每一次都調用一個函數,每個函數又都返回一個值,暫時沒想到怎麼接收,如果有人看到這篇文章,能給一些建議,本人萬分感謝