golang爬蟲初體驗(yàn)

最近在學(xué)習(xí)golang,看網(wǎng)上很多人都喜歡爬豆瓣库物,今天我就寫了一個golang版的爬蟲。對于python爬蟲贷帮,我很了解戚揭,什么dom樹,js異步撵枢,爬蟲技術(shù)棧都是沒問題的民晒。

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

直接上代碼

package main

import (
    "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) {
        // 導(dǎo)演
        director += s.Text()
        //fmt.Println(s.Text())
    })
    fmt.Println("導(dǎo)演:" + 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)
        }
    }
}

以上是最簡單版的沃但,可以優(yōu)化的地方還有很多磁滚,比如使用 協(xié)程,請求頭,反爬蟲機(jī)制等宵晚。


主要使用的就是 goquery這個庫垂攘,當(dāng)然也可以使用正則進(jìn)行匹配。我是拒絕的淤刃。 我很喜歡python中的beautifulsoup晒他。goquery類似jquery,可以直接操作dom樹逸贾。goquery使用的不熟練陨仅,代碼寫的有很多重復(fù)津滞,不優(yōu)雅。

goquery

Go 實(shí)現(xiàn)了類似 jQuery 的功能灼伤,包括鏈?zhǔn)讲僮髡Z法触徐、操作和查詢 HTML 文檔。它基于 Go net/html 包和 CSS 選擇器庫 cascadia饺蔑。由于 net/html 解析器返回的是 DOM 節(jié)點(diǎn)锌介,而不是完整的 DOM 樹,因此猾警,jQuery 的狀態(tài)操作函數(shù)沒有實(shí)現(xiàn)(像 height()孔祸,css(),detach())发皿。

由于 net/html 解析器要求文檔必須是 UTF-8 編碼崔慧,因此 goquery 庫也有此要求。如果文檔不是 UTF-8 編碼穴墅,使用者需要自己轉(zhuǎn)換惶室。進(jìn)行編碼轉(zhuǎn)換,可以使用如下庫:
iconv 的 Go 封裝玄货,如:github.com/djimenez/iconv-go
官方提供的 text 子倉庫皇钞,text/encoding,用于其他編碼和 UTF-8 之間進(jìn)行轉(zhuǎn)換

除了實(shí)現(xiàn)和 jQuery 類似的功能外松捉,在函數(shù)名方面夹界,也盡量和 jQuery 保持一致,也支持鏈?zhǔn)秸Z法隘世。

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

2.1 Document

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

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

因?yàn)?Document 中內(nèi)嵌了一個 Selection 類型,因此械媒,Document 可以直接使用 Selection 類型的方法目锭。

有五種方法獲取一個 Document 實(shí)例,分別是從一個 URL 創(chuàng)建滥沫、從一個 *html.Node 創(chuàng)建侣集、從一個 io.Reader 創(chuàng)建、從一個 *http.Response 創(chuàng)建和從一個已有的 Document Clone 一個兰绣。

2.2 Selection

Selection 代表符合特定條件的節(jié)點(diǎn)集合世分。

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

一般地,得到了 Document 實(shí)例后缀辩,通過 Dcoument.Find 方法獲取一個 Selection 實(shí)例臭埋,然后像 jQuery 一樣使用鏈?zhǔn)秸Z法和方法操作它踪央。

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

1)類似函數(shù)的位置操作

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

2)擴(kuò)大 Selection 集合(增加選擇的節(jié)點(diǎn))

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

3)過濾方法瓢阴,減少節(jié)點(diǎn)集合

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

4)循環(huán)遍歷選擇的節(jié)點(diǎn)

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

5)修改文檔

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

6)檢測或獲取節(jié)點(diǎn)屬性值

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

7)查詢或顯示一個節(jié)點(diǎn)的身份

– Contains()
– Is…()

8)在文檔樹之間來回跳轉(zhuǎn)(常用的查找節(jié)點(diǎn)方法)

– 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 節(jié)點(diǎn)和編譯過的選擇器字符串。Cascadia’s Selector 實(shí)現(xiàn)了該接口荣恐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末液斜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叠穆,更是在濱河造成了極大的恐慌少漆,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硼被,死亡現(xiàn)場離奇詭異示损,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嚷硫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門检访,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人仔掸,你說我怎么就攤上這事脆贵。” “怎么了起暮?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵丹禀,是天一觀的道長。 經(jīng)常有香客問我鞋怀,道長,這世上最難降的妖魔是什么持搜? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任密似,我火速辦了婚禮,結(jié)果婚禮上葫盼,老公的妹妹穿的比我還像新娘残腌。我一直安慰自己,他們只是感情好贫导,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布抛猫。 她就那樣靜靜地躺著,像睡著了一般孩灯。 火紅的嫁衣襯著肌膚如雪闺金。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天峰档,我揣著相機(jī)與錄音败匹,去河邊找鬼寨昙。 笑死,一個胖子當(dāng)著我的面吹牛掀亩,可吹牛的內(nèi)容都是我干的舔哪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼槽棍,長吁一口氣:“原來是場噩夢啊……” “哼捉蚤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炼七,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缆巧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后特石,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盅蝗,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年姆蘸,在試婚紗的時候發(fā)現(xiàn)自己被綠了墩莫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡逞敷,死狀恐怖狂秦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情推捐,我是刑警寧澤裂问,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站牛柒,受9級特大地震影響堪簿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜皮壁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一椭更、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛾魄,春花似錦虑瀑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扔水,卻和暖如春痛侍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背魔市。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工恋日, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膀篮,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓岂膳,卻偏偏與公主長得像誓竿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谈截,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5筷屡? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 27,486評論 1 45
  • ??DOM(文檔對象模型)是針對 HTML 和 XML 文檔的一個 API(應(yīng)用程序編程接口)。 ??DOM 描繪...
    霜天曉閱讀 3,647評論 0 7
  • 一喻鳄、樣式篇 第1章 初識jQuery (1)環(huán)境搭建 進(jìn)入官方網(wǎng)站獲取最新的版本 http://jquery.co...
    凜0_0閱讀 3,386評論 0 44
  • 今天班級組織去棋山春游扼倘,孩子很積極,但凡能和同學(xué)一起參加的活動她都愿意去除呵,今早早早地起床再菊,飯都來不及吃,就和...
    董紫涵閱讀 249評論 0 4
  • 在一個殘疾小學(xué)里,老師一直在悉心呵護(hù)孩子們幼小而脆弱的心靈泛豪。春風(fēng)暖暖吹起孩子們的衣角稠诲,老師帶著孩子們在學(xué)校里的...
    cassiel龘閱讀 1,133評論 0 2