Python 爬蟲(爬取 36Kr)

前一段接到任務(wù),要爬 36Kr 網(wǎng)站首頁的新聞奥吩,當(dāng)時(shí)想的時(shí)應(yīng)該很簡單吧,跟之前爬 “不得姐” 和 “糗百” 應(yīng)該差不多蕊梧,可是實(shí)際操作時(shí)還是遇到了幾個(gè)問題的霞赫。下面把自己的爬取方法分享出來,可能有比這更好的方法肥矢,歡迎交流端衰。

一、分析網(wǎng)頁代碼

我們需要爬取的內(nèi)容在網(wǎng)頁中的位置如下甘改,“最新文章” 下面的新聞旅东。

要爬取的內(nèi)容.png

打開調(diào)試模式,看看代碼十艾,發(fā)現(xiàn)它的外層是一個(gè) <ul class="feed_ul"> 標(biāo)簽抵代,我們需要獲取的信息,在其內(nèi)部的 <li> 標(biāo)簽中忘嫉。

feed_ul.png

打開一個(gè) <li> 標(biāo)簽荤牍,我們看到要獲取的新聞標(biāo)題、圖片庆冕、鏈接位置如下康吵。

<li> 標(biāo)簽內(nèi)容.png

當(dāng)時(shí)想,還是一樣的套路访递,拿到這些標(biāo)簽對(duì)應(yīng)的元素不就行了晦嵌,圖樣圖森破……

二、問題及解決方法

找到了要獲取的信息位置拷姿,開始寫代碼惭载。

#!/usr/bin/env python
#coding:utf-8

from selenium import webdriver

class Kr:
    def __init__(self):
        self.dr = webdriver.Chrome()
        self.dr.get('http://36kr.com/')

    def loadData(self):
        feed_ul = self.dr.find_element_by_class_name('feed_ul')
        # 寫到這卡住了
        
        self.quit()

    def quit(self):
        self.dr.quit()

Kr().loadData()

獲取到 feed_ul 后不會(huì)寫了,因?yàn)槔锩娴?li 標(biāo)簽沒有 class 屬性响巢,這怎么弄棕兼?

查了一下, Selenium 還有一個(gè)定位元素的方法 find_elements_by_tag_name抵乓,通過標(biāo)簽名來獲取元素伴挚,于是寫下了下面的代碼靶衍。

    def loadData(self):
        feed_ul = self.dr.find_element_by_class_name('feed_ul')
        li = feed_ul.find_elements_by_tag_name('li')

        for i in li:
            img_box = i.find_element_by_class_name('img_box')
            print img_box
            # load-img fade 獲取不到
            img = img_box.find_element_by_class_name('load-img fade')
            print img
            break
        
        self.quit()

因?yàn)檎{(diào)試階段我只讓它遍歷一次就 break 了,方便測(cè)試茎芋。img_box 可以成功獲取颅眶,而這個(gè) class 為 load-img fade 的 img 標(biāo)簽卻獲取不到,程序會(huì)報(bào)錯(cuò)田弥。再看看網(wǎng)頁代碼涛酗,發(fā)現(xiàn) img 外層還有一個(gè)無 class 的 div,會(huì)不會(huì)是這個(gè)原因偷厦。

問題1.png

然后又查了一下商叹,發(fā)現(xiàn)了上篇文章中提到的 find_element_by_xpath,通過標(biāo)簽的位置來定位元素只泼,可以理解為標(biāo)簽在網(wǎng)頁中的路徑剖笙。于是又加上了下面的代碼。

img = img_box.find_element_by_xpath('//div/img')
print img.get_attribute('src')

'//div/img' 表示在 img_box 中第一個(gè) div 中的第一個(gè) img 標(biāo)簽请唱。

雖然這樣獲取到了 img 標(biāo)簽弥咪,也打印出了它的 src,但是竟然是這樣一個(gè)圖片十绑。

發(fā)現(xiàn)不對(duì)勁聚至,但是還不知道哪里出錯(cuò)了?? ,既然這樣我干脆直接拿 xpath 來定位 img本橙。

        for i in li:
            xpath = "http://div[@class='am-cf inner_li inner_li_abtest']/a/div[@class='img_box']/div/img"
            img   = i.find_element_by_xpath(xpath)
            print img.get_attribute('src')
            break

可能你會(huì)驚嘆扳躬,這么一長串的 xpath 怎么寫的,一個(gè)一個(gè)找么甚亭?當(dāng)然不是坦报,Chrome 有一個(gè)插件美旧,可以獲取網(wǎng)頁元素的 xpath配乓,這個(gè)我們最后再說矩距,先來看問題卒密。

這樣寫能夠獲取 img菱农,但是打印出的 src 竟然是個(gè) None宏榕,當(dāng)時(shí)也是很迷糊黄橘。后來想可能是網(wǎng)頁通過 Ajax 加載的列表呐矾,因?yàn)榫W(wǎng)速較慢信不,所以當(dāng)時(shí) img 還沒有獲取到 src嘲叔,所以是個(gè) None。為了確認(rèn)自己沒寫錯(cuò)抽活,我打印了一下 alt硫戈。

print img.get_attribute('alt')

可以獲取新聞的標(biāo)題,沒錯(cuò)跋滤丁丁逝?感覺自己寫的是假代碼汁胆。然后我把 break 去掉,又運(yùn)行了一次代碼霜幼。

一臉懵逼
  • 臥槽嫩码!什么情況?怎么都是一樣的罪既?又哪里出問題了铸题?

當(dāng)時(shí)我就這樣,一臉懵逼琢感。經(jīng)歷了這個(gè)打擊后丢间,換了個(gè)路子,我不去拿所有的 li 標(biāo)簽了驹针,拿到 feed_ul 后直接通過 xpath 定位元素烘挫。可以看到 36kr 首頁一共有 28個(gè) li 標(biāo)簽牌捷,其中屬于新聞的只有 20 個(gè),其他的是話題或者是空的涡驮。改寫了如下代碼暗甥。

def loadData(self):
    feed_ul = self.dr.find_element_by_class_name('feed_ul')
    
    i = 1
    while  i <= 28:
        try:
            xpath_head = "http://li[" + str(i) + "]/div[@class='am-cf inner_li inner_li_abtest']/a/div[@class='intro']/h3"
            xpath_href = "http://li[" + str(i) + "]/div[@class='am-cf inner_li inner_li_abtest']/a/div[@class='img_box']/div"
            xpath_img  = "http://li[" + str(i) + "]/div[@class='am-cf inner_li inner_li_abtest']/a/div[@class='img_box']/div/img"

            head  = feed_ul.find_element_by_xpath(xpath_head)
            title = head.text

            href  = feed_ul.find_element_by_xpath(xpath_href)
            url   = 'http://36kr.com' + href.get_attribute('href')

            img   = feed_ul.find_element_by_xpath(xpath_img)
            src   = img.get_attribute('src')

        except Exception as e:
            print 'error'

        else:
            print title
            print url
            print src

        i += 1

    self.quit()

別說,還真好了捉捅,不再是同樣的標(biāo)題撤防,只是除了第一個(gè)新聞能獲取到 src,其他的都是 None棒口。

換了方法后的結(jié)果

又有點(diǎn)小懵逼了寄月,網(wǎng)速慢?不會(huì)啊无牵,下電影還 500kb/s 多呢漾肮!然后又開始各種胡亂試,一度快要放棄茎毁,突然發(fā)現(xiàn)了下圖的情況克懊。

36kr_01.gif

只有處于當(dāng)前窗口內(nèi)的圖片會(huì)顯示,下面的圖片還是灰的七蜘,滾動(dòng)到窗口內(nèi)才會(huì)被加載谭溉。

  • 我是個(gè)天才,這都被我發(fā)現(xiàn)了橡卤!

當(dāng)時(shí)就是這個(gè)想法扮念,發(fā)現(xiàn)了問題還是很開心,不要噴我太水?? 碧库,畢竟第一次遇到這個(gè)問題柜与。既然圖片不在當(dāng)前窗口內(nèi)巧勤,那我就讓瀏覽器滾一滾唄。

img   = feed_ul.find_element_by_xpath(xpath_img)
src   = img.get_attribute('src')

t = 1
while t <= 3:
    if src == None:
        self.dr.execute_script('window.scrollBy(0,200)')
        time.sleep(3)
        src = img.get_attribute('src')
        t += 1
    else:
        break

判斷一下當(dāng)前的 src 是否為 None旅挤,空的話就向下滾 200px(這個(gè)根據(jù)你爬取的網(wǎng)頁自己設(shè)置)踢关,怕網(wǎng)速不給力,再睡 3 秒粘茄,重新獲取一下签舞。因?yàn)榱斜碇写嬖趯n}欄目,避免向下滾動(dòng) 200 正好處于專題位置還是拿不到 src 我又循環(huán)了 3 次柒瓣。為什么是 3 儒搭?事不過三??

  • 關(guān)于 Selenium 對(duì)應(yīng)瀏覽器的操作,以下幾個(gè)也是可能會(huì)用到的
dr.set_window_size(w, h)                    # 設(shè)置瀏覽器寬高
dr.execute_script('window.scrollBy(x, y)')  # 控制瀏覽器滾動(dòng) x 向右 y 向下(相對(duì)于當(dāng)前位置)
dr.execute_script('window.scrollTo(x, y)')  # 控制瀏覽器滾動(dòng) x芙贫、y 為左上角坐標(biāo)(相對(duì)于瀏覽器)
dr.refresh()                                # 刷新頁面

三搂鲫、完整代碼與演示

#!/usr/bin/env python
#coding:utf-8

from selenium import webdriver
import time

class Kr:
    def __init__(self):
        self.dr = webdriver.Chrome()
        self.dr.get('http://36kr.com/')

    def loadData(self):
        feed_ul = self.dr.find_element_by_class_name('feed_ul')
        
        i = 1
        while  i <= 28:
            try:
                xpath_head = "http://li[" + str(i) + "]/div[@class='am-cf inner_li inner_li_abtest']/a/div[@class='intro']/h3"
                xpath_href = "http://li[" + str(i) + "]/div[@class='am-cf inner_li inner_li_abtest']/a/div[@class='img_box']/div"
                xpath_img  = "http://li[" + str(i) + "]/div[@class='am-cf inner_li inner_li_abtest']/a/div[@class='img_box']/div/img"

                head  = feed_ul.find_element_by_xpath(xpath_head)
                title = head.text

                href  = feed_ul.find_element_by_xpath(xpath_href)
                url   = 'http://36kr.com' + href.get_attribute('href')

                img   = feed_ul.find_element_by_xpath(xpath_img)
                src   = img.get_attribute('src')

                t = 1
                while t <= 3:
                    if src == None:
                        self.dr.execute_script('window.scrollBy(0,200)')
                        time.sleep(3)
                        src = img.get_attribute('src')
                        t += 1
                    else:
                        break

            except Exception as e:
                print 'error\n'

            else:
                self.saveData(title, url, src)

            i += 1

        self.quit()

    def saveData(self, title, url, src):
        # 這里拿到數(shù)據(jù)可以存入數(shù)據(jù)庫或其他操作
        print title, '\n', url, '\n', src, '\n'

    def quit(self):
        self.dr.quit()

while 1:
    Kr().loadData()
    time.sleep(600)
演示

歐了,因?yàn)槭桥廊⌒侣劵瞧剑膊簧婕胺摰膯栴}了魂仍,每隔一段時(shí)間調(diào)用一次 loadData() 即可。

對(duì)了拣挪,關(guān)于那個(gè)獲取 xpath 的插件擦酌,可以在 Chrome 的商店中搜索 XPath Helper 下載安裝即可。使用也非常簡單菠劝,shift + command + x 可以開啟赊舶,若無反響刷新下頁面或重啟瀏覽器,按住 shift赶诊,移動(dòng)鼠標(biāo)到想獲取 xpath 的元素上即可笼平。

XPath Helper
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舔痪,隨后出現(xiàn)的幾起案子寓调,更是在濱河造成了極大的恐慌,老刑警劉巖锄码,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捶牢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡巍耗,警方通過查閱死者的電腦和手機(jī)秋麸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炬太,“玉大人灸蟆,你說我怎么就攤上這事。” “怎么了炒考?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵可缚,是天一觀的道長。 經(jīng)常有香客問我斋枢,道長帘靡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任瓤帚,我火速辦了婚禮描姚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘戈次。我一直安慰自己轩勘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布怯邪。 她就那樣靜靜地躺著绊寻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪悬秉。 梳的紋絲不亂的頭發(fā)上澄步,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音和泌,去河邊找鬼村缸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛允跑,可吹牛的內(nèi)容都是我干的王凑。 我是一名探鬼主播搪柑,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼聋丝,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了工碾?” 一聲冷哼從身側(cè)響起弱睦,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渊额,沒想到半個(gè)月后况木,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旬迹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年火惊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奔垦。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屹耐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出椿猎,到底是詐尸還是另有隱情惶岭,我是刑警寧澤寿弱,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站按灶,受9級(jí)特大地震影響症革,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸯旁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一噪矛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧羡亩,春花似錦摩疑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辞居,卻和暖如春楷怒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓦灶。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工鸠删, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贼陶。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓刃泡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親碉怔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烘贴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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

  • 20170531 這幾天重新拾起了爬蟲,算起來有將近5個(gè)月不碰python爬蟲了撮胧。 對(duì)照著網(wǎng)上的程序和自己以前寫的...
    八神蒼月閱讀 14,164評(píng)論 3 44
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案桨踪? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,751評(píng)論 1 92
  • 聲明:本文講解的實(shí)戰(zhàn)內(nèi)容,均僅用于學(xué)習(xí)交流芹啥,請(qǐng)勿用于任何商業(yè)用途锻离! 一、前言 強(qiáng)烈建議:請(qǐng)?jiān)陔娔X的陪同下墓怀,閱讀本文...
    Bruce_Szh閱讀 12,704評(píng)論 6 28
  • 本文分享的大體框架包含以下三部分 (1)首先介紹html網(wǎng)頁汽纠,用來解析html網(wǎng)頁的工具xpath(2)介紹pyt...
    不忘初心c閱讀 2,555評(píng)論 0 14
  • 在這個(gè)多元化的好時(shí)代,允許每個(gè)人選擇自己喜歡的生活方式傀履。你可以選擇出國深造虱朵,可以選擇去大城市打拼,可以選擇呆在小城...
    瓶子小閱讀 211評(píng)論 0 0