golang爬蟲初體驗

來源:互聯網
上載者:User

最近在學習golang,看網上很多人都喜歡爬豆瓣,今天我就寫了一個golang版的爬蟲。對於python爬蟲,我很瞭解,什麼dom樹,js非同步,爬蟲技術棧都是沒問題的。

剛接觸golang爬蟲,今天寫了一個很簡單的爬蟲,就是使用2個庫,一個http、goquery

直接上代碼

package mainimport (    "net/http"    "fmt"    "github.com/PuerkitoBio/goquery"    "strconv")func GetMovie(url string) {    fmt.Println(url)    resp, err := http.Get(url)    if err != nil {        panic(err)    }    //bodyString, err := ioutil.ReadAll(resp.Body)    //fmt.Println(string(bodyString))    if resp.StatusCode != 200 {        fmt.Println("err")    }    doc, err := goquery.NewDocumentFromReader(resp.Body)    if err != nil {        panic(err)    }    //    doc.Find("#content h1").Each(func(i int, s *goquery.Selection) {        // name        fmt.Println("name:" + s.ChildrenFiltered(`[property="v:itemreviewed"]`).Text())        // year        fmt.Println("year:" + s.ChildrenFiltered(`.year`).Text())    })    // #info > span:nth-child(1) > span.attrs    director := ""    doc.Find("#info span:nth-child(1) span.attrs").Each(func(i int, s *goquery.Selection) {        // 導演        director += s.Text()        //fmt.Println(s.Text())    })    fmt.Println("導演:" + director)    //fmt.Println("\n")    pl := ""    doc.Find("#info span:nth-child(3) span.attrs").Each(func(i int, s *goquery.Selection) {        pl += s.Text()    })    fmt.Println("編劇:" + pl)    charactor := ""    doc.Find("#info span.actor span.attrs").Each(func(i int, s *goquery.Selection) {        charactor += s.Text()    })    fmt.Println("主演:" + charactor)    typeStr := ""    doc.Find("#info > span:nth-child(8)").Each(func(i int, s *goquery.Selection) {        typeStr += s.Text()    })    fmt.Println("類型:" + typeStr)}func GetToplist(url string) []string {    var urls []string    resp, err := http.Get(url)    if err != nil {        panic(err)    }    //bodyString, err := ioutil.ReadAll(resp.Body)    //fmt.Println(string(bodyString))    if resp.StatusCode != 200 {        fmt.Println("err")    }    doc, err := goquery.NewDocumentFromReader(resp.Body)    if err != nil {        panic(err)    }    doc.Find("#content div div.article ol li div div.info div.hd a").Each(func(i int, s *goquery.Selection) {        // year        fmt.Printf("%v", s)        herf, _ := s.Attr("href")        urls = append(urls, herf)    })    return urls}func main() {    url := "https://movie.douban.com/top250?start="    var urls []string    var newUrl string    fmt.Println("%v", urls)    for i := 0; i < 10; i++ {        start := i * 25        newUrl = url + strconv.Itoa(start)        urls = GetToplist(newUrl)        for _, url := range urls {            GetMovie(url)        }    }}

以上是最簡單版的,可以最佳化的地方還有很多,比如使用 協程,要求標頭,反爬蟲機制等。


主要使用的就是 goquery這個庫,當然也可以使用正則進行匹配。我是拒絕的。 我很喜歡python中的beautifulsoup。goquery類似jquery,可以直接操作dom樹。goquery使用的不熟練,代碼寫的有很多重複,不優雅。

goquery

Go 實現了類似 jQuery 的功能,包括鏈式操作文法、操作和查詢 HTML 文檔。它基於 Go net/html 包和 CSS 選取器庫 cascadia。由於 net/html 解析器返回的是 DOM 節點,而不是完整的 DOM 樹,因此,jQuery 的狀態操作函數沒有實現(像 height(),css(),detach())。

由於 net/html 解析器要求文檔必須是 UTF-8 編碼,因此 goquery 庫也有此要求。如果文檔不是 UTF-8 編碼,使用者需要自己轉換。進行編碼轉換,可以使用如下庫:
iconv 的 Go 封裝,如:github.com/djimenez/iconv-go
官方提供的 text 子倉庫,text/encoding,用於其他編碼和 UTF-8 之間進行轉換

除了實現和 jQuery 類似的功能外,在函數名方面,也盡量和 jQuery 保持一致,也支援鏈式文法。

2 goquery 提供的主要類型和方法

2.1 Document

Document 代表一個將要被操作的 HTML 文檔,不過,和 jQuery 不同,它裝載的是 DOM 文檔的一部分。

type Document struct {    *Selection    Url      *url.URL    rootNode *html.Node}

因為 Document 中內嵌了一個 Selection 類型,因此,Document 可以直接使用 Selection 類型的方法。

有五種方法擷取一個 Document 執行個體,分別是從一個 URL 建立、從一個 *html.Node 建立、從一個 io.Reader 建立、從一個 *http.Response 建立和從一個已有的 Document Clone 一個。

2.2 Selection

Selection 代表符合特定條件的節點集合。

type Selection struct {    Nodes    []*html.Node    document *Document    prevSel  *Selection}

一般地,得到了 Document 執行個體後,通過 Dcoument.Find 方法擷取一個 Selection 執行個體,然後像 jQuery 一樣使用鏈式文法和方法操作它。

Selection 類型提供的方法可以分為如下幾大類(注意,3個點(…)表示有重載的方法):

1)類似函數的位置操作

– Eq()
– First()
– Get()
– Index…()
– Last()
– Slice()

2)擴大 Selection 集合(增加選擇的節點)

– Add…()
– AndSelf()
– Union(), which is an alias for AddSelection()

3)過濾方法,減少節點集合

– End()
– Filter…()
– Has…()
– Intersection(), which is an alias of FilterSelection()
– Not…()

4)迴圈遍曆選擇的節點

– Each()
– EachWithBreak()
– Map()

5)修改文檔

– After…()
– Append…()
– Before…()
– Clone()
– Empty()
– Prepend…()
– Remove…()
– ReplaceWith…()
– Unwrap()
– Wrap…()
– WrapAll…()
– WrapInner…()

6)檢測或擷取節點屬性值

– Attr(), RemoveAttr(), SetAttr()
– AddClass(), HasClass(), RemoveClass(), ToggleClass()
– Html()
– Length()
– Size(), which is an alias for Length()
– Text()

7)查詢或顯示一個節點的身份

– Contains()
– Is…()

8)在文檔樹之間來回跳轉(常用的尋找節點方法)

– Children…()
– Contents()
– Find…()
– Next…()
– Parent[s]…()
– Prev…()
– Siblings…()

2.3 Matcher 介面

type Matcher interface {    Match(*html.Node) bool    MatchAll(*html.Node) []*html.Node    Filter([]*html.Node) []*html.Node}

該介面定義了一些方法,用於匹配 HTML 節點和編譯過的選取器字串。Cascadia’s Selector 實現了該介面。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.