這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
有兩個不錯的庫:
https://github.com/PuerkitoBio/goquery
一個是
http://code.google.com/p/go.net/html
html是html的解析器,把html文本解析出來,goquery基於html包,在此基礎上結合cascadia 包(一個css選取器工具),實作類別似於jquery的功能,操作html非常方便。
使用goquery來尋找,選擇相應的html節點,但如果要對選擇的節點進行修改,刪除操作,還需要深入使用html包。
html包把html文本解析為一個樹,這個樹有很多Node組成,操作的核心就在於對Node的操作。
用幾個例子來說明一下吧:
doc, err := goquery.NewDocument("http://sports.sina.com.cn")
產生一個goquery的doc。
goquery用的最多的是Find函數,類似於jquery的$(),可以選擇dom結構。
例1:
dhead := doc.Find("head")dcharset := dhead.Find("meta[http-equiv]")charset, _ := dcharset.Attr("content")
這個例子用來找出頁面的charset。
例2:
logo := doc.Find("#retina_logo")
這個是根據html中的id來選擇dom
例3:
bread := doc.Find("div.blkBreadcrumbLink")
選擇doc中class為blkBreadcrumbLink的div
例4:
var faceImg stringvar innerImg = []string{}dom_body.Find("div.img_wrapper").Each(func(i int, s *goquery.Selection) {imgpath, exists := s.Find("img").Attr("src")if !exists {return}if i == 0 {faceImg = imgpath}innerImg = append(innerImg, imgpath)})
找出所有class為img_wrapper的div,然後在每個div下搜尋img,擷取img的src
例5:
dom_node := doc.Find("[bosszone='ztTopic']").Find("a")
這個是根據屬性/值來尋找相應的元素
如果要對html進行編輯操作,需要使用html.Node,這裡提供一個清洗div的代碼,使用了遞迴:
func clear_dom(pn *html.Node, isgb2312 bool) error {var err errorfor nd := pn.FirstChild; nd != nil; {switch nd.Type {case html.ElementNode:tn := strings.ToLower(nd.Data)//fmt.Printf("element node: %s\n", tn)if tn == "script" || tn == "style" {// delete the elementtmp := ndnd = tmp.NextSiblingpn.RemoveChild(tmp)} else if tn == "a" {tmp := ndnd = nd.NextSiblingif err = convert_dom(tmp, isgb2312); err != nil {return err}} else if tn == "span" {tmp := ndnd = nd.NextSiblingclear_dom(tmp, isgb2312)} else {tmp := ndnd = nd.NextSiblingif err = convert_dom(tmp, isgb2312); err != nil {return err}}case html.CommentNode:tmp := ndnd = tmp.NextSiblingpn.RemoveChild(tmp)case html.TextNode:tmp := ndnd = nd.NextSiblingif err = convert_dom(tmp, isgb2312); err != nil {return err}default:nd = nd.NextSibling}}return nil}
其中conver_dom是對node節點的text進行轉碼操作,如果不需要,可以忽略。
func Nodehtml(n *html.Node) string {var buf = bytes.NewBuffer([]byte{})html.Render(buf, n)return buf.String()}func Nodetext(node *html.Node) string {if node.Type == html.TextNode {// Keep newlines and spaces, like jQueryreturn node.Data} else if node.FirstChild != nil {var buf bytes.Bufferfor c := node.FirstChild; c != nil; c = c.NextSibling {buf.WriteString(Nodetext(c))}return buf.String()}return ""}
上面的兩個函數,分別擷取節點的html代碼和text代碼。html代碼和text代碼的區別是,html代碼是原封不動的html代碼,text代碼僅僅顯示html代碼的內容,例如一段html: 例子,它的text代碼是”例子”