flysnow_org
最近研究Go爬蟲相關的知識,使用到goquery這個庫比較多,尤爲是對爬取到的HTML進行選擇和查找匹配的內容時,goquery的選擇器使用尤爲多,並且還有不少不經常使用但又頗有用的選擇器,這裏總結下,以供參考。前端
若是你們之前作過前端開發,對jquery不會陌生,goquery相似jquery,它是jquery的go版本實現。使用它,能夠很方便的對HTML進行處理。jquery
基於HTML Element 元素的選擇器
apdom.Find("div")
func main() { html := `<body> <div>DIV1</div> <div>DIV2</div> <span>SPAN</span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) } 複製代碼
divbodyspan
ID 選擇器
dividid
func main() { html := `<body> <div id="div1">DIV1</div> <div>DIV2</div> <span>SPAN</span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("#div1").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) } 複製代碼
Element ID 選擇器
id#iddom.Find(#id)Find(#id)
dividdiv1Find(div#div1)
Find(element#id)
Class選擇器
classclassIDFind(".class")
func main() { html := `<body> <div id="div1">DIV1</div> <div class="name">DIV2</div> <span>SPAN</span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find(".name").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) } 複製代碼
classnamediv
Element Class 選擇器
classidFind(element.class)
屬性選擇器
一個HTML元素都有本身的屬性以及屬性值,因此咱們也能夠經過屬性和值篩選元素。
func main() { html := `<body> <div>DIV1</div> <div class="name">DIV2</div> <span>SPAN</span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div[class]").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) } 複製代碼
div[class]divclassdiv
剛剛上面這個示例是採用是否存在某個屬性爲篩選器,同理,咱們能夠篩選出屬性爲某個值的元素。
dom.Find("div[class=name]").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) 複製代碼
classnamediv
classhref
除了徹底相等,還有其餘匹配方式,使用方式相似,這裏統一列舉下,再也不舉例
選擇器 | 說明 |
---|---|
Find("div[lang]") | 篩選含有lang屬性的div元素 |
Find("div[lang=zh]") | 篩選lang屬性爲zh的div元素 |
Find("div[lang!=zh]") | 篩選lang屬性不等於zh的div元素 |
Find("div[lang¦=zh]") | 篩選lang屬性爲zh或者zh-開頭的div元素 |
Find("div[lang*=zh]") | 篩選lang屬性包含zh這個字符串的div元素 |
Find("div[lang~=zh]") | 篩選lang屬性包含zh這個單詞的div元素,單詞以空格分開的 |
Find("div[lang$=zh]") | 篩選lang屬性以zh結尾的div元素,區分大小寫 |
Find("div[lang^=zh]") | 篩選lang屬性以zh開頭的div元素,區分大小寫 |
Find("div[id][lang=zh]")
parent>child選擇器
Find("parent>child")
func main() { html := `<body> <div lang="ZH">DIV1</div> <div lang="zh-cn">DIV2</div> <div lang="en">DIV3</div> <span> <div>DIV4</div> </span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("body>div").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) } 複製代碼
bodydivDIV一、DIV二、DIV3DIV4body
DIV4bodydiv>
dom.Find("body div").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) 複製代碼
prev+next相鄰選擇器
假設咱們要篩選的元素沒有規律,可是該元素的上一個元素有規律,咱們就可使用這種下一個相鄰選擇器來進行選擇。
func main() { html := `<body> <div lang="zh">DIV1</div> <p>P1</p> <div lang="zh-cn">DIV2</div> <div lang="en">DIV3</div> <span> <div>DIV4</div> </span> <p>P2</p> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div[lang=zh]+p").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) } 複製代碼
P1
DIV1Find("div[lang=zh]+p")P
("prev+next")
flysnow_org
prev~next選擇器
有相鄰就有兄弟,兄弟選擇器就不必定要求相鄰了,只要他們共有一個父元素就能夠。
dom.Find("div[lang=zh]~p").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) 複製代碼
+~P2P2P1DIV1
("prev~next")+~
內容過濾器
有時候咱們使用選擇器選擇出來後後,但願再過濾一下,這時候就用到過濾器了,過濾器有不少,咱們先講內容過濾器這一種。
dom.Find("div:contains(DIV2)").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) 複製代碼
Find(":contains(text)")divDIV2DIV2
Find(":empty")
Find(":has(selector)")contains
dom.Find("span:has(div)").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) 複製代碼
divspan
:first-child過濾器
:first-childFind(":first-child")
func main() { html := `<body> <div lang="zh">DIV1</div> <p>P1</p> <div lang="zh-cn">DIV2</div> <div lang="en">DIV3</div> <span> <div style="display:none;">DIV4</div> <div>DIV5</div> </span> <p>P2</p> <div></div> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div:first-child").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Html()) }) } 複製代碼
Find("div")div:first-childDIV1DIV4DIV
:first-of-type過濾器
:first-child:first-child:first-of-type
func main() { html := `<body> <div lang="zh">DIV1</div> <p>P1</p> <div lang="zh-cn">DIV2</div> <div lang="en">DIV3</div> <span> <p>P2</p> <div>DIV5</div> </span> <div></div> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div:first-of-type").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Html()) }) } 複製代碼
DIV4P2:first-childDIV5P2:first-of-typeDIV5divP2div
:last-child 和 :last-of-type過濾器
:first-child:first-of-type
:nth-child(n) 過濾器
:first-child:nth-child(1)n
func main() { html := `<body> <div lang="zh">DIV1</div> <p>P1</p> <div lang="zh-cn">DIV2</div> <div lang="en">DIV3</div> <span> <p>P2</p> <div>DIV5</div> </span> <div></div> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div:nth-child(3)").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Html()) }) } 複製代碼
DIV2DIV2body
:nth-of-type(n) 過濾器
:nth-of-type(n):nth-child(n):nth-of-type(1):first-of-type
nth-last-child(n) 和:nth-last-of-type(n) 過濾器
這兩個和上面的相似,只不過是倒序開始計算的,最後一個元素被當成了第一個。你們本身測試下看看效果,很明顯。
:only-child 過濾器
Find(":only-child")
func main() { html := `<body> <div lang="zh">DIV1</div> <span> <div>DIV5</div> </span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div:only-child").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Html()) }) } 複製代碼
DIV5spanDIV1
:only-of-type 過濾器
DIV1Find(":only-of-type")div:only-of-type:only-of-typeDIV1
選擇器或(|)運算
divspanFind("selector1, selector2, selectorN")
func main() { html := `<body> <div lang="zh">DIV1</div> <span> <div>DIV5</div> </span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div,span").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Html()) }) } 複製代碼
小結
goquery 是解析HTML網頁必備的利器,在爬蟲抓取網頁的過程當中,靈活的使用goquery不一樣的選擇器,可讓咱們的抓取工做事半功倍,大大提高爬蟲的效率。
flysnow_org