goquery爬蟲實(shí)踐案例

之前一直以為"爬蟲"是一門高大上的技術(shù),但自從遇見goquery之后,發(fā)現(xiàn)爬取網(wǎng)站也可以這么簡(jiǎn)單。

goquery是一個(gè)使用go語(yǔ)言寫的HTML解析庫(kù),它最大的特點(diǎn)就是可以像使用jQuery那樣,來(lái)方便地操作DOM文檔,相信做過(guò)web開發(fā)的人員很快就能掌握其使用方法。

github項(xiàng)目地址

selector(選擇器)

我認(rèn)為selector是這個(gè)框架的靈魂所在,就是因?yàn)閷?shí)現(xiàn)了類似于jQuery的DOM選擇功能,才使得框架非常容易使用。

以下是幾個(gè)常用的選擇器,看著是不是很熟悉:

s.Find("div")      // 元素選擇
s.Find("#Content") // id選擇
s.Find(".content") // class選擇
s.Find("div[id=Content]") // 屬性選擇
s.Find("div>p") // 子元素選擇
s.Find("div+p") // 相鄰元素選擇
s.Find("div~p") // 兄弟元素選擇

s.Find("#Content").Text() // 獲取對(duì)象的文本內(nèi)容
s.Find("#Content").Html() // 獲取對(duì)象的html
s.Find("#Content").Attr("src") // 獲取對(duì)象的src屬性值

這里推薦一篇文章,非常詳細(xì)地介紹了goquery選擇器的各種用法。

實(shí)戰(zhàn)

介紹方面網(wǎng)上有寫的很好的文章,我也沒(méi)有什么新的內(nèi)容補(bǔ)充,所以直接進(jìn)入實(shí)戰(zhàn)部分了。

頁(yè)面分析

這里我用goquery爬了豆瓣電影(心疼豆瓣,好多人把豆瓣電影當(dāng)爬蟲練手),通過(guò)對(duì)豆瓣電影主頁(yè)進(jìn)行分析,發(fā)現(xiàn)電影列表是通過(guò)ajax獲取的,然而goquery針對(duì)的只是靜態(tài)的DOM文檔,對(duì)于動(dòng)態(tài)的數(shù)據(jù)它就無(wú)能為力了。

通過(guò)觀察,找到獲取電影列表的url,發(fā)現(xiàn)是get方法獲取的,那么我們就可以編程構(gòu)造get請(qǐng)求獲取電影列表進(jìn)行處理了,其有type、tag、sort、page_limit、page_start這幾個(gè)參數(shù),操作一下頁(yè)面很容易獲取這幾個(gè)參數(shù)值。

使用goquery爬取的是具體的電影詳情頁(yè)面,也沒(méi)有搞得多復(fù)雜,只獲取一些基本信息用于展示即可。

爬取電影詳情頁(yè)信息

其實(shí)文字上也沒(méi)什么好描述的,看代碼來(lái)的更直觀明了,先講一下步驟,首先自然是要get請(qǐng)求獲取頁(yè)面內(nèi)容了,然后創(chuàng)建一個(gè)goquery解析器,最后使用選擇器獲取需要的數(shù)據(jù)即可。

func GetMovieInfo(url string) *MovieParam {
    // get請(qǐng)求獲取頁(yè)面
    res, err := http.Get(url)
    if err != nil {
        log.Println(err)
        return nil
    }
    defer res.Body.Close()
    if res.StatusCode != 200 {
        log.Printf("status code error: %d %s", res.StatusCode, res.Status)
        return nil
    }

    // 創(chuàng)建解析器
    doc, err := goquery.NewDocumentFromReader(res.Body)
    if err != nil {
        log.Println(err)
        return nil
    }

    param := MovieParam{}
    doc.Find("#content").Each(func(i int, s *goquery.Selection) {
        param.Year = s.Find("h1 .year").Text() // 年份
        param.Img, _ = s.Find("#mainpic img").Attr("src") // 圖片
        param.Summary, _ = s.Find("#link-report span[property]").Html() // 摘要
        param.Rating_people = comhelper.StringToInt(s.Find(".rating_people span[property]").Text()) // 評(píng)論人數(shù)
        star, _ := s.Find(".bigstar").Attr("class") // 星級(jí)值
        param.Bigstar = comhelper.StringToInt(star[len(star)-2 : len(star)])
        stars_five := s.Find(".stars5+div+span").Text() // 5星的比例值
        param.Stars_five = comhelper.StringToFloat(stars_five[0:len(stars_five)-1], 64)
        stars_four := s.Find(".stars4+div+span").Text() // 4星的比例值
        param.Stars_four = comhelper.StringToFloat(stars_four[0:len(stars_four)-1], 64)
        stars_three := s.Find(".stars3+div+span").Text() // 3星的比例值
        param.Stars_three = comhelper.StringToFloat(stars_three[0:len(stars_three)-1], 64)
        stars_two := s.Find(".stars2+div+span").Text() // 2星的比例值
        param.Stars_two = comhelper.StringToFloat(stars_two[0:len(stars_two)-1], 64)
        stars_one := s.Find(".stars1+div+span").Text() // 1星的比例值
        param.Stars_one = comhelper.StringToFloat(stars_one[0:len(stars_one)-1], 64)

        // 圖片轉(zhuǎn)換成base64
        img_url, _ := _download_img(param.Img)
        new_img, err := comhelper.ImgToBase64(img_url)
        if err == nil && new_img != "" {
            param.Img = new_img
        }

        s.Find("#info").Each(func(ii int, ss *goquery.Selection) {
            info, _ := ss.Html()
            param.Director = ss.Find("a[rel*=directedBy]").Text() // 導(dǎo)演
            film_length, _ := ss.Find("span[property*=runtime]").Attr("content") // 時(shí)長(zhǎng)
            param.Film_length = comhelper.StringToInt(film_length)
            param.Release_date = ss.Find("span[property*=initialReleaseDate]").Text() // 上映日期

            // 獲取類型
            tags := ""
            ss.Find("span[property*=genre]").Each(func(i int, s *goquery.Selection) {
                if tags == "" {
                    tags += s.Text()
                } else {
                    tags += "/" + s.Text()
                }
            })
            param.Tags = tags

            // 獲取主演
            actor := ""
            ss.Find("a[rel*=starring]").Each(func(i int, s *goquery.Selection) {
                if actor == "" {
                    actor += s.Text()
                } else {
                    actor += "/" + s.Text()
                }
            })
            param.Actor = actor

            c_start := strings.Index(info, "<span class=\"pl\">制片國(guó)家/地區(qū):</span>")
            c_end := strings.Index(info, "<span class=\"pl\">語(yǔ)言")
            param.Country = comhelper.TrimHtml(info[c_start+44 : c_end])
        })
    })

    return &param
}

那些有id、class或者特殊屬性的字段最容易獲取了,比較麻煩的是那些沒(méi)有明顯特征的字段,只能通過(guò)字符串截取的方法獲取了,不過(guò)也都是些常規(guī)操作,整個(gè)流程下來(lái)沒(méi)什么難點(diǎn),這也說(shuō)明了goquery的簡(jiǎn)單易用。

成果展示

成果展示以及源碼點(diǎn)擊這里(抱歉,服務(wù)器太貴了,已脫坑)

遇到的問(wèn)題

頻繁訪問(wèn)會(huì)導(dǎo)致ip被鎖住,不過(guò)我也只是練習(xí),所以只是爬取了一點(diǎn)數(shù)據(jù)用來(lái)展示。

圖片會(huì)有訪問(wèn)權(quán)限的問(wèn)題,所以我轉(zhuǎn)換成了base64格式存到數(shù)據(jù)庫(kù)里,不過(guò)在頁(yè)面渲染的時(shí)候由于數(shù)據(jù)量過(guò)大導(dǎo)致頁(yè)面加載巨慢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,797評(píng)論 1 45
  • 問(wèn)答題47 /72 常見瀏覽器兼容性問(wèn)題與解決方案? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 14,109評(píng)論 1 92
  • 前言 爬蟲就是請(qǐng)求網(wǎng)站并提取數(shù)據(jù)的自動(dòng)化程序,其中請(qǐng)求,提取,自動(dòng)化是爬蟲的關(guān)鍵。Python作為一款出色的膠水語(yǔ)...
    王奧OX閱讀 3,636評(píng)論 1 8
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,158評(píng)論 4 61
  • 越來(lái)越多的團(tuán)隊(duì)將業(yè)務(wù)依托于微信,甚至很多中小型企業(yè)靠著微信吃飯。 群控和云控挺熱鬧的,去年下半年火到現(xiàn)在,經(jīng)歷了幾...
    行奕日記閱讀 316評(píng)論 0 1

友情鏈接更多精彩內(nèi)容