go?語言爬蟲庫goquery的具體使用
爬蟲介紹
爬蟲,又稱網(wǎng)頁抓取、網(wǎng)絡(luò)蜘蛛或網(wǎng)絡(luò)爬蟲,是一種自動(dòng)瀏覽互聯(lián)網(wǎng)并從網(wǎng)站上獲取信息的程序或腳本。它通過模擬人類瀏覽器的行為,按照預(yù)設(shè)的規(guī)則和策略遍歷互聯(lián)網(wǎng)上的網(wǎng)頁,并將所獲取的數(shù)據(jù)存儲(chǔ)下來進(jìn)行進(jìn)一步處理和分析。
爬蟲在我們生活中可以產(chǎn)生的東西有很多
搜索引擎索引構(gòu)建:搜索引擎會(huì)使用爬蟲抓取互聯(lián)網(wǎng)上的網(wǎng)頁,分析其內(nèi)容并建立索引,以便用戶在搜索時(shí)能夠快速找到相關(guān)結(jié)果。
數(shù)據(jù)分析與研究:數(shù)據(jù)分析師和研究人員可以編寫爬蟲來收集特定領(lǐng)域的信息,如電子商務(wù)網(wǎng)站的商品價(jià)格、評(píng)論等,用于市場趨勢分析、競品監(jiān)測、消費(fèi)者行為研究等。
新聞聚合:新聞聚合類應(yīng)用通過爬蟲從多個(gè)新聞網(wǎng)站獲取最新的文章標(biāo)題、摘要以及鏈接,為用戶提供一站式的新聞閱讀體驗(yàn)。
社交媒體監(jiān)控:針對(duì)社交媒體平臺(tái)的爬蟲可以抓取公開的帖子、評(píng)論等內(nèi)容,用于輿情分析、熱點(diǎn)話題追蹤、品牌口碑監(jiān)測等。
企業(yè)信息抓取:商業(yè)情報(bào)機(jī)構(gòu)或公司可能需要抓取工商注冊(cè)、專利申請(qǐng)、招聘信息等公開的企業(yè)數(shù)據(jù),進(jìn)行行業(yè)分析、潛在客戶挖掘等工作。
教育資源整理:教育領(lǐng)域中,爬蟲可以用來搜集網(wǎng)絡(luò)課程資源、學(xué)術(shù)論文、圖書資料等,并進(jìn)行整理歸類。
網(wǎng)站性能檢測:某些類型的爬蟲(例如蜘蛛俠)用于模擬大量用戶訪問以測試網(wǎng)站性能,檢查是否存在服務(wù)器響應(yīng)延遲、頁面加載慢等問題。
法律合規(guī)審計(jì):在網(wǎng)絡(luò)合規(guī)性審查中,爬蟲可以用于查找非法或侵權(quán)內(nèi)容,協(xié)助監(jiān)管部門進(jìn)行網(wǎng)絡(luò)環(huán)境凈化。
在生活中爬蟲其實(shí)可以做很多事情,鑒于本文是一個(gè)入門教程,就接下來會(huì)以一個(gè)爬取csdn網(wǎng)頁增加流量的列子逐步介紹和完善我們的爬蟲程序。
goquery介紹
GoQuery是專為Go(Golang)語言設(shè)計(jì)的一個(gè)強(qiáng)大的HTML解析和查詢庫。它模仿了jQuery的API風(fēng)格,使得在Go中處理HTML文檔變得簡單且直觀。
GoQuery主要用于網(wǎng)頁抓?。╓eb Scraping),能夠通過CSS選擇器來定位、遍歷和操作HTML元素。你可以使用它來提取網(wǎng)頁中的特定數(shù)據(jù)、修改DOM結(jié)構(gòu)或進(jìn)行其他與HTML文檔相關(guān)的操作。
安裝
go get github.com/PuerkitoBio/goquery
創(chuàng)建文檔
doc,err := goquery.NewDocumentFromReader(reader io.Reader) doc,err := goquery.NewDocument(url string) doc,err := goquery.NewDocument(strings.NewReader("<p>這里是內(nèi)容</p>")
內(nèi)置函數(shù)
1) array.go : 類似數(shù)組的定位函數(shù)
Eq(index int) *Selection //根據(jù)索引獲取某個(gè)節(jié)點(diǎn)集 First() *Selection //獲取第一個(gè)子節(jié)點(diǎn)集 Get(index int) *html.Node //根據(jù)索引獲取一個(gè)節(jié)點(diǎn) Index...() int //返回選擇對(duì)象中第一個(gè)元素的位置 Last() *Selection //獲取最后一個(gè)子節(jié)點(diǎn)集 Slice(start, end int) *Selection //根據(jù)起始位置獲取子節(jié)點(diǎn)集
2)expand.go : 擴(kuò)展函數(shù)
Add...() AndSelf() Union() // AddSelection()的別名
3)filter.go : 過濾函數(shù), 用于減少選擇范圍
End() Filter...() Has...() Intersection() //FilterSelection()的別名 Not...()
4)iteration.go : 循環(huán)遍歷選擇節(jié)點(diǎn)的函數(shù)
Each(f func(int, *Selection)) *Selection //遍歷 EachWithBreak(f func(int, *Selection) bool) *Selection //可中斷遍歷 Map(f func(int, *Selection) string) (result []string) //返回字符串?dāng)?shù)組
5)manipulation.go : 修改文檔的函數(shù)
After...() Append...() Before...() Clone() Empty() Prepend...() Remove...() ReplaceWith...() Unwrap() Wrap...() WrapAll...() WrapInner...()
6)property.go :檢測或獲取節(jié)點(diǎn)屬性值的函數(shù)
Attr*(), RemoveAttr(), SetAttr() //獲取,移除,設(shè)置屬性的值 AttrOr(e string,d string) //獲取對(duì)應(yīng)的標(biāo)簽屬性。這個(gè)可以設(shè)置第二個(gè)參數(shù)。獲取的默認(rèn)值,如果獲取不到默認(rèn)調(diào)用對(duì)應(yīng)默認(rèn)值 AddClass(), HasClass(), RemoveClass(), ToggleClass() Html() //獲取該節(jié)點(diǎn)的html Length() //返回該Selection的元素個(gè)數(shù) Size() //Length()的別名 Text() //獲取該節(jié)點(diǎn)的文本值
7)query.go : 節(jié)點(diǎn)查找的函數(shù)
Contains() //獲取當(dāng)前節(jié)點(diǎn)下的所有節(jié)點(diǎn) Is...()
8)traversal.go : 遍歷HTML文檔樹的函數(shù)
在文檔樹之間來回跳轉(zhuǎn)(常用的查找節(jié)點(diǎn)方法)
Children...() //返回selection中各個(gè)節(jié)點(diǎn)下的孩子節(jié)點(diǎn) Contents() //獲取當(dāng)前節(jié)點(diǎn)下的所有節(jié)點(diǎn) Find...() //查找獲取當(dāng)前匹配的元素 Next...() *Selection //獲取下一個(gè)兄弟節(jié)點(diǎn)集,下一個(gè)元素 NextAll() *Selection //獲取后面所有兄弟節(jié)點(diǎn)集 Parent[s]...() Prev...() *Selection //前一個(gè)兄弟節(jié)點(diǎn)集,上一個(gè)元素 Siblings...()
9)type.go : goQuery定義的類型
Document Selection Matcher
10)utilities.go : 輔助函數(shù)的定義(而不是* Selection上的方法),jQuery沒有該部分,但對(duì)goquery很有用
NodeName OuterHtml
利用NewDocumentFromReader方法獲取主頁信息
NewDocumentFromReader 是GoQuery庫中的一個(gè)函數(shù),用于從io.Reader接口讀取的HTML數(shù)據(jù)創(chuàng)建一個(gè)新的文檔對(duì)象。對(duì)于文檔對(duì)象是什么我們會(huì)在下文經(jīng)性講解。func NewDocumentFromReader(reader io.Reader) (*Document, error)
以下我們查找主頁信息的代碼,studycodeday是博主本人的主頁,想要訪問自己的主頁,只需要把studycodeday改成自己的用戶id就行。
func main() { // 通過http發(fā)送get請(qǐng)求 req, err := http.Get("https://blog.csdn.net/studycodeday") if err != nil { slog.Error("訪問主頁失敗") } defer req.Body.Close() // 解析請(qǐng)求體 doc, err := goquery.NewDocumentFromReader(req.Body) // 讓請(qǐng)求體按照html格式輸出,也有Text()按照文本輸出的方法 fmt.Println(doc.Html()) }
效果
Document介紹
在GoQuery庫中,Document是代表整個(gè)HTML文檔的對(duì)象。它是對(duì)原始HTML內(nèi)容解析后形成的DOM樹的抽象表示,提供了與jQuery類似的接口來操作和查詢HTML元素。
*goquery.Document主要有以下特點(diǎn)和功能:
- 初始化:
從本地文件或io.Reader讀取:使用goquery.NewDocumentFromReader(reader io.Reader)從任何實(shí)現(xiàn)了io.Reader接口的對(duì)象(如文件、HTTP響應(yīng)體等)創(chuàng)建一個(gè)Document對(duì)象。 - 查找元素:
使用CSS選擇器進(jìn)行查找:doc.Find(selector string)返回一個(gè)新的Selection對(duì)象,該對(duì)象包含了所有匹配給定CSS選擇器的元素。 - 遍歷和操作元素:
Each(func(int, *goquery.Selection))方法用于迭代選區(qū)中的每個(gè)元素,并對(duì)其執(zhí)行回調(diào)函數(shù)。
提供了類似jQuery的方法,如.Children()獲取子元素、.Parents()獲取父元素等。 - 屬性操作:
Attr(name string) (string, bool):獲取首個(gè)匹配元素的指定屬性值及其是否存在。
SetAttr(name, value string):為所有匹配元素設(shè)置指定屬性的值。 - 文本和HTML內(nèi)容操作:
Text() string:獲取所有匹配元素的合并文本內(nèi)容。
Html() string:獲取首個(gè)匹配元素的HTML內(nèi)容。
其他功能:
goquery.Document對(duì)象是GoQuery庫的核心組成部分,它封裝了對(duì)HTML文檔進(jìn)行各種復(fù)雜查詢和操作的能力。
通過查詢獲取文章信息
css選擇器介紹
獲取文章需要我們通過查詢的方式,goquery提供了能夠通過CSS選擇器來定位元素。
其類型包括但不限于以下幾種:
- 基本選擇器:
- *:匹配所有元素。
- element:匹配所有指定類型的元素,如 div、span 等。
- .class:匹配具有指定類名的元素,如 .myClass。
- #id:匹配ID為指定值的元素,如 #header。
- 屬性選擇器:
- [attribute]:匹配具有指定屬性的元素,不論該屬性值為何。
- [attribute=value]:匹配屬性值等于指定值的元素,如 [href=“http://example.com”]。
- [attribute^=value]、[attribute$=value]、[attribute*=value]:分別匹配屬性值以指定值開頭、結(jié)尾或包含指定值的元素。
- 層次選擇器:
- parent > child:匹配作為指定父元素直接子元素的所有child元素。
- ancestor descendant:匹配在ancestor元素內(nèi)的所有descendant元素(無論嵌套多深)。
- prev + next:匹配緊跟在prev元素之后的next元素。
- prev ~ siblings:匹配prev元素之后的所有同輩siblings元素。
- 偽類選擇器:
- :first-child、:last-child、:nth-child(n):匹配某個(gè)元素在其父元素內(nèi)是第一個(gè)、最后一個(gè)或第n個(gè)子元素的情況。
- :not(selector):排除匹配給定選擇器的元素。
goquery中的選擇器
Find():doc.Find(selector string)
根據(jù)給定的CSS選擇器在當(dāng)前選區(qū)(Selection)中查找匹配的元素。例如,doc.Find(“h1”)會(huì)找到所有
標(biāo)簽。
Filter():
selection.Filter(selector string)
在當(dāng)前選區(qū)中過濾出符合指定CSS選擇器的元素子集。
Eq():
selection.Eq(index int)
返回當(dāng)前選區(qū)中索引為index的單個(gè)元素。索引從0開始。
First() 和 Last():selection.First()
selection.Last()
分別返回當(dāng)前選區(qū)中的第一個(gè)或最后一個(gè)元素。
Next() 和 Prev():selection.NextAll()
selection.PrevAll()
獲取當(dāng)前元素之后的所有同輩元素或之前的所有同輩元素。
Children():
selection.Children()
獲取當(dāng)前選區(qū)中所有直接子元素。
Parents() 和 Closest():selection.Parents()
selection.Closest(selector string)
Parents()返回當(dāng)前選區(qū)中所有父級(jí)元素,而Closest()返回最近的且匹配給定CSS選擇器的祖先元素。
Attr():attr, exists := selection.Attr(attributeName string)
獲取當(dāng)前選區(qū)中首個(gè)元素的屬性值,exists用于判斷該屬性是否存在。
Each():selection.Each(func(i int, s *goquery.Selection) {})
遍歷當(dāng)前選區(qū)中的每一個(gè)元素,并對(duì)每個(gè)元素執(zhí)行一個(gè)函數(shù)。
獲取主頁中的文章鏈接
首先我們要打開f12調(diào)試工具,找到我們需要爬取數(shù)據(jù)的所在的具體位置。
由上圖可知我們的文章連接在擁有class=“mainContent” 的div盒子里,這個(gè)盒子包括了二十個(gè)含有 class=“blog-list-box” 的article標(biāo)簽,我們所需要的內(nèi)容就在article標(biāo)簽下面的a標(biāo)簽的herf中。
這里我們采用層次原則器 ancestor descendant:匹配在ancestor元素內(nèi)的所有descendant元素(無論嵌套多深)。把文章盒子提取來之后我們還需要通過Each方法遍歷輸出a標(biāo)簽中的href屬性的值
// 通過http發(fā)送get請(qǐng)求 req, err := http.Get("https://blog.csdn.net/studycodeday") if err != nil { slog.Error("訪問主頁失敗") } defer req.Body.Close() // 解析請(qǐng)求體 doc, err := goquery.NewDocumentFromReader(req.Body) //fmt.Println(doc.Find(".mainContent .blog-list-box").Length()) doc.Find(".mainContent .blog-list-box").Each(func(i int, s *goquery.Selection) { fmt.Println(s.Find("a").Attr("href")) })
效果
爬取
以上我們就完成了主頁文章信息的爬取,我們只需要吧內(nèi)容存在數(shù)組中,經(jīng)行爬取訪問即可。
代碼
func main() { var urls = make([]string, 0, 20) // 通過http發(fā)送get請(qǐng)求 req, err := http.Get("https://blog.csdn.net/studycodeday") if err != nil { slog.Error("訪問主頁失敗") } defer req.Body.Close() // 解析請(qǐng)求體 doc, err := goquery.NewDocumentFromReader(req.Body) //fmt.Println(doc.Find(".mainContent .blog-list-box").Length()) doc.Find(".mainContent .blog-list-box").Each(func(i int, s *goquery.Selection) { url, _ := s.Find("a").Attr("href") //添加到數(shù)組中 urls = append(urls, url) }) for _, url := range urls { _, err = http.Get(url) if err != nil { slog.Error("訪問網(wǎng)頁失?。? + url) } fmt.Println("訪問成功:" + url) time.Sleep(time.Duration(rand.Int31n(60)) * time.Second) } }
效果
總結(jié)
雖然我們實(shí)現(xiàn)了爬取csdn網(wǎng)頁,但是仍然存在許多問題:
- 沒有代理頻繁訪問容易封ip,造成無法訪問csdn
- 爬取只能爬取前二十篇文章,該解決方法是參考該api,只需要把username改成自己的id即可
- 沒有進(jìn)行請(qǐng)求偽裝,隨時(shí)可能被封
到此這篇關(guān)于go 語言爬蟲庫goquery的具體使用的文章就介紹到這了,更多相關(guān)go 語言爬蟲庫goquery 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang模擬實(shí)現(xiàn)帶超時(shí)的信號(hào)量示例代碼
這篇文章主要給大家介紹了關(guān)于golang模擬實(shí)現(xiàn)帶超時(shí)的信號(hào)量的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09Go的gin參數(shù)校驗(yàn)中的validator庫詳解
這篇文章主要介紹了Go的gin參數(shù)校驗(yàn)之validator庫,使用 validator 以后,只需要在定義結(jié)構(gòu)體時(shí)使用 binding 或 validate tag標(biāo)識(shí)相關(guān)校驗(yàn)規(guī)則,就可以進(jìn)行參數(shù)校驗(yàn)了,而不用自己單獨(dú)去寫常見的校驗(yàn)規(guī)則,需要的朋友可以參考下2023-08-08GoFrame框架Scan類型轉(zhuǎn)換實(shí)例
這篇文章主要為大家介紹了GoFrame框架Scan類型轉(zhuǎn)換的實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Golang使用gin模板渲染base64圖片出現(xiàn)#ZgotmplZ的解決辦法
這篇文章主要介紹了Golang使用gin模板渲染base64圖片出現(xiàn)#ZgotmplZ的的場景復(fù)現(xiàn)和解決辦法,文中通過代碼示例講解的非常詳細(xì),對(duì)大家解決問題有一定的幫助,需要的朋友可以參考下2024-05-05