goquery爬蟲實(shí)踐案例

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

goquery是一個(gè)使用go語言寫的HTML解析庫,它最大的特點(diǎn)就是可以像使用jQuery那樣涝涤,來方便地操作DOM文檔媚狰,相信做過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)上有寫的很好的文章货裹,我也沒有什么新的內(nèi)容補(bǔ)充嗤形,所以直接進(jìn)入實(shí)戰(zhàn)部分了。

頁面分析

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

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

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

爬取電影詳情頁信息

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

func GetMovieInfo(url string) *MovieParam {
    // get請(qǐng)求獲取頁面
    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\">語言")
            param.Country = comhelper.TrimHtml(info[c_start+44 : c_end])
        })
    })

    return &param
}

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

成果展示

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

遇到的問題

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末根资,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子同窘,更是在濱河造成了極大的恐慌玄帕,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件想邦,死亡現(xiàn)場(chǎng)離奇詭異裤纹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門鹰椒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锡移,“玉大人,你說我怎么就攤上這事漆际∠海” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵奸汇,是天一觀的道長(zhǎng)施符。 經(jīng)常有香客問我,道長(zhǎng)擂找,這世上最難降的妖魔是什么戳吝? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮婴洼,結(jié)果婚禮上骨坑,老公的妹妹穿的比我還像新娘。我一直安慰自己柬采,他們只是感情好欢唾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粉捻,像睡著了一般礁遣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肩刃,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天祟霍,我揣著相機(jī)與錄音,去河邊找鬼盈包。 笑死沸呐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呢燥。 我是一名探鬼主播崭添,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼叛氨!你這毒婦竟也來了呼渣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤寞埠,失蹤者是張志新(化名)和其女友劉穎屁置,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仁连,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蓝角,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片使鹅。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颇象,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出并徘,到底是詐尸還是另有隱情,我是刑警寧澤扰魂,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布麦乞,位于F島的核電站,受9級(jí)特大地震影響劝评,放射性物質(zhì)發(fā)生泄漏姐直。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一蒋畜、第九天 我趴在偏房一處隱蔽的房頂上張望声畏。 院中可真熱鬧,春花似錦姻成、人聲如沸插龄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽均牢。三九已至,卻和暖如春才睹,著一層夾襖步出監(jiān)牢的瞬間徘跪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工琅攘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留垮庐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓坞琴,卻偏偏與公主長(zhǎng)得像哨查,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子置济,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

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