Python爬蟲之爬豆瓣電影數(shù)據(jù)

0x000 前言

最近和公司的IOS談起脆霎,以前我們是做移動端总处,現(xiàn)在已經(jīng)和前端混為一談了。 也是 睛蛛, 做了一年多的Android 鹦马,一直都是在寫界面展示數(shù)據(jù),寫交互 忆肾,存儲簡單的數(shù)據(jù) 荸频,最主要的業(yè)務(wù)數(shù)據(jù)與業(yè)務(wù)邏輯都在服務(wù)器端,這讓我有種離了服務(wù)端客冈,我們只能玩玩單機和聯(lián)機了 旭从。作為曾經(jīng)的web開發(fā),深知服務(wù)端的重要性郊酒,我們要想做一款好的產(chǎn)品遇绞,沒有服務(wù)端是萬萬不能的 , 而我們做移動端的更是要知曉一些服務(wù)端的知識 燎窘。

我有一個夢想摹闽,做一款屬于自己的產(chǎn)品 ,但苦于沒有足夠的數(shù)據(jù)褐健,于是就開始了我的Python爬蟲之旅 付鹿。(如果有時間澜汤,我會寫如何從零收集數(shù)據(jù)-->服務(wù)器端的建立 --> 客戶端的編寫 , 一整套教程)

0x001 Python基礎(chǔ)

Python是一門很簡潔的語言 舵匾, 因為市面上介紹Python語法的教程很多 俊抵, 大多數(shù)都很好 ,我這里就不啰嗦了 坐梯, 下面貼出我看過的網(wǎng)站:

廖雪峰 - Python教程
簡明Python教程

0x002 網(wǎng)絡(luò)爬蟲

網(wǎng)絡(luò)爬蟲是一個自動提取網(wǎng)頁的程序徽诲,它為搜索引擎從萬維網(wǎng)上下載網(wǎng)頁,是搜索引擎的重要組成吵血。傳統(tǒng)爬蟲從一個或若干初始網(wǎng)頁的URL開始谎替,獲得初始網(wǎng)頁上的URL,在抓取網(wǎng)頁的過程中蹋辅,不斷從當(dāng)前頁面上抽取新的URL放入隊列,直到滿足系統(tǒng)的一定停止條件钱贯。[來自百度]

我們通過URL讓爬蟲來爬取我們想要的內(nèi)容 , 根據(jù)我們的規(guī)則進行深入爬取 侦另, 比如說 秩命, 我們想要爬取正在上映的電影數(shù)據(jù) , 并下載電影海報褒傅,其他的內(nèi)容我們忽略掉弃锐,那么我們就需要根據(jù)網(wǎng)頁內(nèi)容的規(guī)則來制訂,哪些內(nèi)容是我們需要的樊卓,哪些是我們不需要的拿愧。

0x003 爬取豆瓣電影數(shù)據(jù)

第一步 : 打開豆瓣電影 , 分析網(wǎng)頁結(jié)構(gòu)

我們爬取的網(wǎng)址是 https://movie.douban.com/cinema/nowplaying/shenzhen/ 碌尔,里面有一個的模塊叫正在上映 浇辜, 我們就解析這個模塊,其他的內(nèi)容我們忽略掉唾戚。chrome(firefox)按f12查看網(wǎng)頁結(jié)構(gòu)柳洋。

網(wǎng)頁結(jié)構(gòu)

我們可以用元素選擇工具,選中我們要分析的數(shù)據(jù)叹坦,firebug控制臺就會將選中html結(jié)構(gòu)展示出來熊镣。我們通過分析 , 我們想要的數(shù)據(jù)是在一個ul標(biāo)簽里面募书,每一個li標(biāo)簽就是一部電影的數(shù)據(jù)绪囱,我們只需要取出里面的li中的數(shù)據(jù)即可。豆瓣的前臺使用了數(shù)據(jù)綁定的技術(shù) 莹捡,這為我們獲取數(shù)據(jù)鬼吵,方便了不少 ,我們直接取出li中的屬性就可以將電影信息獲取到了 篮赢。

第二步 : 下載網(wǎng)頁內(nèi)容

我們需要將網(wǎng)頁中的數(shù)據(jù)提取出去 齿椅, 就需要先將網(wǎng)頁內(nèi)容下載下來琉挖,寫Java程序的朋友應(yīng)該知道 , 如果使用Java內(nèi)置網(wǎng)絡(luò)請求涣脚,將網(wǎng)頁數(shù)據(jù)下載下來示辈,那將要寫多少行代碼,實話說遣蚀,Java的網(wǎng)絡(luò)請求真的很不友好矾麻,幸而Java社區(qū)異常強大,涌現(xiàn)了一批又一批比較好用的網(wǎng)絡(luò)請求框架妙同,如OkHttp,liteHttp等等射富,大大簡化了我們的工作。但是粥帚,在Python中,將一個網(wǎng)頁數(shù)據(jù)下載下來限次,只需要一行 芒涡。

with request.urlopen('https://movie.douban.com/cinema/nowplaying/shenzhen/') as response:

這是Python內(nèi)置的urllib下的requests對象,將下載好的二進制數(shù)據(jù)封裝在response對象里面卖漫,使用readlines方法就可以將其讀取出來 费尽。

from urllib import request
from urllib import parse

# 打開鏈接,并得到返回值
with request.urlopen('https://movie.douban.com/cinema/nowplaying/shenzhen/') as response:
      conent_list = response.readlines() # 得到一個byte類型的list
      #打印內(nèi)容
      for content in conent_list:
          print(content .decode()) # 因為content是byte類型羊始,所以需要解碼成str類型

雖然內(nèi)置urlib可以完成我們的需求旱幼,但是我們不會用系統(tǒng)內(nèi)置,因為還是比較麻煩突委,我們將使用富有盛名的requets庫柏卤,雖然名字和系統(tǒng)內(nèi)置的差不多,但是確實截然不同的庫 匀油。系統(tǒng)庫是在urllib模塊下缘缚,而requests就在requests模塊下 。

安裝requests

pip install requests

example

# url 請求地址
# headers 請求頭
url = 'https://movie.douban.com/cinema/nowplaying/shenzhen/'
res = requests.get(url,headers=headers)
res.text() # 得到請求的文本內(nèi)容

好戲敌蚜,馬上開場

第三步 : 解析網(wǎng)頁內(nèi)容

解析是使用的Python內(nèi)置的Html解析器桥滨,類似Java的jsoup.jar提供的api 。都是通過遍歷Html dom樹來進行分析弛车,判斷需要的tag 齐媒,然后進行屬性解析。Python正在強大的Html解析器是纷跛,XPath解析喻括,也是scrapy爬蟲庫內(nèi)置的解析器 ,當(dāng)然還是有beautifulsoup 忽舟。

1.引入HTMLPaser

from html.parser import HTMLParser

2.新建解析類双妨,繼承HTMLPaser

class MoviesParser(HTMLParser):

3.overload handle_starttag方法 淮阐, 解析標(biāo)簽

class MoviesParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        # 電影列表list集合
        self.movies = []
        # 標(biāo)簽是否在li標(biāo)簽中的標(biāo)識
        self.img_into_movie = False
        self.a_into_movie = False

    def handle_starttag(self, tag, attrs):
        # 因為屬性都是key=val形式 , 所以根據(jù)屬性名稱取值
        def _attr(attrs,attr_name):
            for attr in attrs:
                if attr[0] == attr_name:
                    return attr[1]
            return None

        # 取出屬性值 , 根據(jù)每個Item的特征取值 刁品,因為有些Item的屬性可能會重復(fù) 泣特, 所以要盡量找出差異性,這樣才能保證數(shù)據(jù)的準(zhǔn)確性
        if tag == 'li' and _attr(attrs,'data-title') and _attr(attrs,'data-category') == 'nowplaying':
            movie = {}
            movie['title'] = _attr(attrs,'data-title')
            movie['score'] = _attr(attrs,'data-score')
            movie['star'] = _attr(attrs,'data-star')
            movie['duration'] = _attr(attrs,'data-duration')
            movie['region'] = _attr(attrs,'data-region')
            movie['director'] = _attr(attrs,'data-director')
            movie['actors'] = _attr(attrs,'data-actors')
            self.movies.append(movie)
            self.img_into_movie = True
            self.a_into_movie = True

        #獲取海報圖片
        if tag == 'img' and self.img_into_movie:
            self.img_into_movie = False
            img_src = _attr(attrs,'src')
            movie = self.movies[len(self.movies) -1]
            movie['poster_url'] = img_src
            # 下載圖片
            donwload_poster_url(img_src)
        
        # 解析a標(biāo)簽挑随,提取電影詳情頁的Url
        if tag == 'a' and self.a_into_movie:
            if _attr(attrs,'data-psource') == 'title':
                self.a_into_movie = False
                movie_url = _attr(attrs,'href')
                movie = self.movies[len(self.movies) -1]
                movie['movie_url'] = movie_url

這是爬蟲中最關(guān)鍵的部分状您,數(shù)據(jù)解析是保證數(shù)據(jù)正確的性的地方,解析沒做好兜挨,就可能存在很多臟數(shù)據(jù)膏孟,這是我們應(yīng)當(dāng)避免的 。

第四步 : 下載圖片

# 下載圖片
def donwload_poster_url(url):
    res = requests.get(url)
    file_name = str.split(url,'/')[-1]
    file_path = 'poster_img/' + file_name
    print('download img file_path = ',file_path)
    with open(file_path,'wb') as f:
        f.write(res.content)

我們直接使用requests庫拌汇,get圖片地址柒桑,得到圖片的二進制數(shù)據(jù),再見二進制數(shù)據(jù)寫入到文件中噪舀,這樣我們的圖片文件就下載好了魁淳。

完整源碼

# 使用requests爬豆瓣正在上映的電影
from html.parser import HTMLParser
import requests


class MoviesParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.movies = []
        self.img_into_movie = False
        self.a_into_movie = False

    def handle_starttag(self, tag, attrs):
        # 根據(jù)屬性名稱取值
        def _attr(attrs,attr_name):
            for attr in attrs:
                if attr[0] == attr_name:
                    return attr[1]
            return None
        # 取出屬性值
        if tag == 'li' and _attr(attrs,'data-title') and _attr(attrs,'data-category') == 'nowplaying':
            movie = {}
            movie['title'] = _attr(attrs,'data-title')
            movie['score'] = _attr(attrs,'data-score')
            movie['star'] = _attr(attrs,'data-star')
            movie['duration'] = _attr(attrs,'data-duration')
            movie['region'] = _attr(attrs,'data-region')
            movie['director'] = _attr(attrs,'data-director')
            movie['actors'] = _attr(attrs,'data-actors')
            self.movies.append(movie)
            self.img_into_movie = True
            self.a_into_movie = True

        #獲取海報圖片
        if tag == 'img' and self.img_into_movie:
            self.img_into_movie = False
            img_src = _attr(attrs,'src')
            movie = self.movies[len(self.movies) -1]
            movie['poster_url'] = img_src
            donwload_poster_url(img_src)

        if tag == 'a' and self.a_into_movie:
            if _attr(attrs,'data-psource') == 'title':
                self.a_into_movie = False
                movie_url = _attr(attrs,'href')
                movie = self.movies[len(self.movies) -1]
                movie['movie_url'] = movie_url


# 下載圖片
def donwload_poster_url(url):
    res = requests.get(url)
    file_name = str.split(url,'/')[-1]
    file_path = 'poster_img/' + file_name
    print('download img file_path = ',file_path)
    with open(file_path,'wb') as f:
        f.write(res.content)


def douban_movies(url):
    #首先構(gòu)建請求頭 ,模擬瀏覽器請求頭
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}
    # # 打開鏈接与倡,并得到返回值
    res = requests.get(url,headers=headers)
    # 創(chuàng)建Html解析器
    moviesParser = MoviesParser()
    # 解析Html數(shù)據(jù)
    moviesParser.feed(res.text)
    return moviesParser.movies

if __name__ == '__main__':
    url_str = 'https://movie.douban.com/cinema/nowplaying/shenzhen/'
    movies_res = douban_movies(url_str)

    import json
    json_str = json.dumps(movies_res,sort_keys=True,indent=4,separators=(',',': '))
    # 打印json數(shù)據(jù)
    print(json_str)

從下載數(shù)據(jù)到解析Html界逛,只用了七十多行 ,包含了注釋和空格纺座,真是人生苦短息拜,我用Python

0x004 結(jié)語

Python確實是一個比較簡潔的語言净响,學(xué)起來也相對比較輕松少欺,各種庫應(yīng)有盡有,可以作為獲取數(shù)據(jù)的不二選擇 别惦。其實狈茉,解析Html 還可以簡化,使用Xpath更加簡潔掸掸,幾行代碼就可以搞定氯庆,在后續(xù)的文章中,我會逐一介紹 扰付。

有時候感覺文字的表現(xiàn)力真是太弱了堤撵,特別是對于技術(shù)文章,因為涉及的多羽莺,很多時候?qū)懼鴮懼蛦铝耸底颍缓髣h掉 。 俗話說:子不如表 盐固, 表不如圖荒给,圖不如視頻 丈挟。最近關(guān)注了一個簡書的作者,他做了一系列的視頻志电,講得挺好的曙咽,我思考著,要不要出個爬蟲的視頻教程 挑辆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末例朱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鱼蝉,更是在濱河造成了極大的恐慌洒嗤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魁亦,死亡現(xiàn)場離奇詭異渔隶,居然都是意外死亡,警方通過查閱死者的電腦和手機洁奈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門派撕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人睬魂,你說我怎么就攤上這事《贫模” “怎么了氯哮?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長商佛。 經(jīng)常有香客問我喉钢,道長,這世上最難降的妖魔是什么良姆? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任肠虽,我火速辦了婚禮,結(jié)果婚禮上玛追,老公的妹妹穿的比我還像新娘税课。我一直安慰自己,他們只是感情好痊剖,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布韩玩。 她就那樣靜靜地躺著,像睡著了一般陆馁。 火紅的嫁衣襯著肌膚如雪找颓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天叮贩,我揣著相機與錄音击狮,去河邊找鬼佛析。 笑死,一個胖子當(dāng)著我的面吹牛彪蓬,可吹牛的內(nèi)容都是我干的寸莫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼寞焙,長吁一口氣:“原來是場噩夢啊……” “哼储狭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捣郊,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤辽狈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后呛牲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刮萌,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年娘扩,在試婚紗的時候發(fā)現(xiàn)自己被綠了着茸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡琐旁,死狀恐怖涮阔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情灰殴,我是刑警寧澤敬特,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站牺陶,受9級特大地震影響伟阔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掰伸,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一皱炉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狮鸭,春花似錦合搅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至廊谓,卻和暖如春梳猪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工春弥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留呛哟,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓匿沛,卻偏偏與公主長得像扫责,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子逃呼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

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