【Go 入門學習】第一篇關於 Go 的博客--Go 爬蟲初體驗

1、寫在前面

  其實早就該寫這一篇博客了,爲何一直沒有寫呢?還不是由於忙不過來(實際上只是由於太懶了)。不過好了,如今終於要開始寫這一篇博客了。在看這篇博客以前,可能須要你對 Go 這門語言有些基本的瞭解,好比基礎語法之類的。話很少說,進入正題。html

 

2、Go 環境配置

1.安裝配置

  在學習一門語言時,第一步就是環境配置了,Go 也不例外,下面就是 Windows 下 Go 開發環境的配置過程了。git

  首先你須要下載 Go 的安裝包,能夠打開 Go 語言中文網下載,地址爲:https://studygolang.com/dlgithub

  下載完成後打開安裝(例如安裝到 E:\Go 目錄),而後配置環境變量,將安裝目錄下的 bin 目錄路徑加入環境變量中。這一步完成後打開命令行,輸入 go version,若出現版本信息則代表配置成功。golang

2.配置 GOPATH 和 GOROOT

  除了要將 bin 目錄加入到環境變量中,還要配置 GOPATH 和 GOROOT,步驟以下:正則表達式

  在用戶變量中新建變量 GOPATH:數組

  

   在系統變量中新建變量 GOROOT:併發

  

 3. 選擇 IDE

  在 IDE 的選擇上,我比較推薦使用 jetbrains 家的 GoLand,功能強大,使用起來也很方便。函數

 

3、下載網頁

  下載網頁使用的是 Go 中原生的 http 庫,在使用前須要導包,和 Python 同樣用 import 導入便可。若是要發送 GET 請求,能夠直接使用 http 中的 Get() 方法,例如:post

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "net/http"
 6 )
 7 
 8 func main () {
 9     html, err := http.Get("https://www.baidu.com/")
10     if err != nil {
11         fmt.Println(err)
12     }
13     fmt.Println(html)
14 }

  Get() 方法有兩個返回值,html 表示請求的結果,err 表示錯誤,這裏必須對 err 作判斷,Go 語言的錯誤機制就是這樣,這裏很少作解釋。學習

  這麼用起來確實很簡單,可是不能本身設置請求頭,若是要構造請求頭的話能夠參考下面的例子:

1 req, _ := http.NewRequest("GET", url, nil)
2 // Set User-Agent
3 req.Header.Add("UserAgent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36")
4 client := &http.Client{}
5 resp, err := client.Do(req)

 

4、解析網頁

1.解析庫選擇

  Go 語言中能夠用來解析網頁的庫也是很齊全的,XPath、CSS 選擇器和正則表達式都能用。這裏我用的是 htmlquery,這個庫使用的是 Xpath 選擇器。htmlquery 是用於 HTML 的 XPath 數據提取庫,可經過 XPath 表達式從 HTML 文檔中提取數據。Xpath 語法就不提了,畢竟用 Python 寫爬蟲的時候沒少用。

  先說下 htmlquery 的安裝吧,通常會推薦你使用以下命令安裝:

go get github.com/antchfx/htmlquery

  可是你懂的,出於某些緣由就下載不下來,怎麼辦呢?對於這種能在 GitHub 上找到的庫直接 clone 到本地就好了,記得要複製到你的 GOAPTH 下

2.使用 htmlquery

  在使用 htmlquery 這個庫的時候,可能會報錯說缺乏 golang.org\x\text,和上面的解決辦法同樣,去 GitHub 上找,而後 clone 下來。

  下面是 htmlquery 中常用的方法及相應含義:

func Parse(r io.Reader) (*html.Node, error):  返回給定 Reader 的 HTML 的解析樹。

func Find(top *html.Node, expr string) []*html.Node: 搜索與指定 XPath 表達式匹配的 html.Node。

func FindOne(top *html.Node, expr string) *html.Node: 搜索與指定 XPath 表達式匹配的 html.Node,並返回匹配的第一個元素,可簡單理解爲 FindOne = Find[0]

func InnerText(n *html.Node) string: 返回對象的開始和結束標記之間的文本。
 
func SelectAttr(n *html.Node, name string) (val string): 返回指定名稱的屬性值。

func OutputHTML(n *html.Node, self bool) string: 返回包含標籤名稱的文本。

   下面是使用 htmlquery 解析網頁的代碼:

 1 // Used to parse html
 2 func parse(html string) {
 3     // Parse html
 4     root, _ := htmlquery.Parse(strings.NewReader(html))
 5     titleList := htmlquery.Find(root, `//*[@id="post_list"]/div/div[2]/h3/a/text()`)
 6     hrefList := htmlquery.Find(root, `//*[@id="post_list"]/div/div[2]/h3/a/@href`)
 7     authorList := htmlquery.Find(root, `//*[@id="post_list"]/div/div[2]/div/a/text()`)
 8 
 9     // Traverse the result
10     for i := range titleList {
11         blog := BlogInfo{}
12         blog.title = htmlquery.InnerText(titleList[i])
13         blog.href = htmlquery.InnerText(hrefList[i])
14         blog.author = htmlquery.InnerText(authorList[i])
15         fmt.Println(blog)
16     }
17 }

  須要注意的是因爲在 Go 語言中不支持使用單引號來表示字符串,而要使用反引號「`」和雙引號來表示字符串。而後由於 Find() 方法返回的是一個數組,於是須要遍歷其中每個元素,使用 for 循環遍歷便可。在 for 循環中使用到的 BlogInfo 是一個結構體,表示一個博客的基本信息,定義以下:

1 // Used to record blog information
2 type BlogInfo struct {
3     title string
4     href string
5     author string
6 }

 

5、Go 併發

     在 Go 語言中使用 go 關鍵字開啓一個新的 go 程,也叫 goroutine,開啓成功以後,go 關鍵字後的函數就將在開啓的 goroutine 中運行,並不會阻塞當前進程的執行,因此要用 Go 來寫併發仍是很容易的。例如:

 1 baseUrl := "https://www.cnblogs.com/"
 2 for i := 2; i < 4; i ++ {
 3     url := baseUrl + "#p" + strconv.Itoa(i)
 4     // fmt.Println(url)
 5     go request(url)
 6 }
 7 
 8 // Wait for goroutine
 9 time.Sleep(2 * time.Second)
10 request(baseUrl)

  這裏除了在主進程中有一個 request(),還開啓了兩個 go 程來執行 request()。不過要注意的是,一旦主進程結束,其他 Go 程也會結束,因此我這裏加了一個兩秒鐘的等待時間,用於讓 Go 程先結束。

 

6、體驗總結

  因爲我自己纔剛開始學習 Go,就還有不少東西沒有學到,因此這個初體驗其實還有不少沒寫到的地方,好比數據保存,去重問題等等,後面會去多看看 Go 的官方文檔。固然了,對我來講,要寫爬蟲的話仍是會用 Python 來寫的,不過仍是得花時間學習新知識,好比使用 Go 作開發,熟悉掌握 Go 語言就是個人下一目標了。

 

  完整代碼已上傳到 GitHub

相關文章
相關標籤/搜索