手把手教你爬取豆瓣Top250

最近在家看了些關於爬蟲的資料,發一個小項目給想學爬蟲的人帶個路~儘可能地介紹一下每步的理由和做法。關於爬蟲的資料太多了,初學者很容易迷失在各種各樣的框架、庫中(比如博主),也是借這個小項目給大家理一下爬蟲的學習路程!
一般而言,其實爬蟲就是三個步驟:(1)網頁爬取(2)數據解析(3)數據存儲
網頁爬取: 獲取你需要的網頁的HTML代碼(這部分需要注意一下反爬蟲機制),常用的庫有:urllib或者requests,二者選其一即可
數據解析: 從獲取的HTML代碼中得到自己想要的數據,常用的庫:lxml(xpath語法)或者beautifulSoup4或者re(正則),三者最好都要學,初學者可以從beautifulSoup4開始學。在我看來,數據解析是整個爬蟲的精華也是難點。
數據存儲: 很容易理解,即把解析到的數據存儲爲自己想要的格式。

網頁爬取

使用requests庫
按下F12,進入開發者模式,選中Network,然後刷新,可以看到一個數據包,選中,查看其Headers。豆瓣的對爬蟲很友好,我們的headers中只需要僞裝兩項:Referer和User-Agent,將瀏覽器中的複製下來即可!
在這裏插入圖片描述

import requests
#設置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests庫發送get請求
text = response.text #獲取html代碼
#存儲得到的html代碼
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)

有一點需要說明,爲什麼是發送get請求,也是在NetWork-Headers中得知的,一般而言,常用的是get和post請求。
在這裏插入圖片描述
我們可以得到html.txt如下:
在這裏插入圖片描述

數據解析

使用lxml庫
首先先對HTML代碼分析,同樣是在開發者模式下,定位到整個需要爬取的頁面,可以看到在class = grid_view的<ol>下面有一串的<li>標籤,每個<li>標籤即爲一個電影。
在這裏插入圖片描述

from lxml import etree
import requests
#設置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests庫發送get請求
text = response.text #獲取html代碼
#存儲得到的html代碼
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class爲grid_view的ol標籤,返回的是列表,所以取第0項去除列表
movie = ul.xpath("./li")[0] #查找該ol標籤下的li標籤,這裏取第一項
print(etree.tostring(movie, encoding='utf-8').decode('utf-8')) #打印li標籤中的HTML代碼

得到HTML代碼如下:

        <li>
            <div class="item">
                <div class="pic">
                    <em class="">1</em>
                    <a href="https://movie.douban.com/subject/1292052/">
                        <img width="100" alt="肖申克的救贖" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" class="">
                    </a>
                </div>
                <div class="info">
                    <div class="hd">
                        <a href="https://movie.douban.com/subject/1292052/" class="">
                            <span class="title">肖申克的救贖</span>
                                    <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                                <span class="other">&nbsp;/&nbsp;月黑高飛(港)  /  刺激1995(臺)</span>
                        </a>


                            <span class="playable">[可播放]</span>
                    </div>
                    <div class="bd">
                        <p class="">
                            導演: 弗蘭克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·羅賓斯 Tim Robbins /...<br>
                            1994&nbsp;/&nbsp;美國&nbsp;/&nbsp;犯罪 劇情
                        </p>

                        
                        <div class="star">
                                <span class="rating5-t"></span>
                                <span class="rating_num" property="v:average">9.7</span>
                                <span property="v:best" content="10.0"></span>
                                <span>1857327人評價</span>
                        </div>

                            <p class="quote">
                                <span class="inq">希望讓人自由。</span>
                            </p>
                    </div>
                </div>
            </div>
        </li>
        <li>

繼續分析,這裏取三種數據爲例
title:可以看到<img>標籤的alt屬性即爲電影名
img:可以看到<img>標籤的src屬性即爲圖片地址
rating:可以看到class屬性爲star的<div>標籤下的class屬性爲rating_num的<span>中的文字內容即爲評分

from lxml import etree
import requests
#設置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests庫發送get請求
text = response.text #獲取html代碼
#存儲得到的html代碼
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class爲grid_view的ol標籤,返回的是列表,所以取第0項去除列表
movie = ul.xpath("./li")[0] #查找該ol標籤下的li標籤,這裏取第一項
title = movie.xpath(".//img/@alt")[0]
img = movie.xpath(".//img/@src")[0]
rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0]
print("名稱:", title, "\n圖片: ", img, "\n評分:", rating)

運行結果
在這裏插入圖片描述

數據存儲

電影的圖片下載到文件夾,其他的數據存儲到json文件中,這裏還是用肖申克的救贖爲例。

import json
from lxml import etree
import requests
#設置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests庫發送get請求
text = response.text #獲取html代碼
#存儲得到的html代碼
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class爲grid_view的ol標籤,返回的是列表,所以取第0項去除列表
movie = ul.xpath("./li")[0] #查找該ol標籤下的li標籤,這裏取第一項
title = movie.xpath(".//img/@alt")[0] #名稱
img = movie.xpath(".//img/@src")[0] #圖片url
rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0] #評分
movieUrl = movie.xpath(".//a/@href")[0] #電影鏈接
quote = movie.xpath(".//span[@class='inq']/text()")[0] #語錄
info = {"名稱": title, "評分": rating, "鏈接": movieUrl, "語錄": quote} #信息存儲爲字典
#信息保存到json文件
with open('movieTop250.json', 'w', encoding='utf-8') as f:
    f.write(json.dumps(info, ensure_ascii=False, indent=4, separators=(',', ':')))
#保存圖片
with requests.get(img, stream=True, headers=headers) as resp:
    with open('./img/1.jpg', 'wb') as fd:
        for chunk in resp.iter_content():
            fd.write(chunk)

完整代碼

以上完成了肖申克的救贖的信息存儲和圖片存儲,其他電影的同理,只需要增加一些循環即可。
另外我們爬取的https://movie.douban.com/top250只有25個電影,其他還有9個頁面,點下一個頁面的url爲https://movie.douban.com/top250?start=25&filter=,可以發現規律,每次start遞進25。
整理一下代碼:

import requests
from lxml import etree
import json
#設置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
cnt = 1
infos = []
for i in range(0, 250, 25):
    url = 'https://movie.douban.com/top250?start='+str(i)+'&filter=' # url值
    response = requests.get(url, headers=headers) #使用requests庫發送post請求
    text = response.text #獲取html代碼
    #存儲得到的html代碼
    # with open('./html.txt', 'w', encoding='utf-8') as f:
    #     f.write(text)
    html = etree.HTML(text)
    ul = html.xpath("//ol[@class='grid_view']")[0] #查找class爲grid_view的ol標籤,返回的是列表,所以取第0項去除列表
    movies = ul.xpath("./li") #查找該ol標籤下的li標籤,這裏取第一項
    # print(etree.tostring(movies, encoding='utf-8').decode('utf-8')) #打印li標籤中的HTML代碼
    for movie in movies:
        title = movie.xpath(".//img/@alt")[0] #名稱
        img = movie.xpath(".//img/@src")[0] #圖片url
        rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0] #評分
        movieUrl = movie.xpath(".//a/@href")[0] #電影鏈接
        quote = movie.xpath(".//span[@class='inq']/text()") #語錄
        quote = " " if not quote  else quote[0]
        info = {"名稱": title, "排名": cnt, "評分": rating, "鏈接": movieUrl, "語錄": quote} #信息存儲爲字典
        infos.append(info)
        #保存圖片
        with requests.get(img, stream=True, headers=headers) as resp:
            with open('./img/'+str(cnt)+'.jpg', 'wb') as fd:
                cnt += 1
                for chunk in resp.iter_content():
                    fd.write(chunk)
#信息保存到json文件
with open('movieTop250.json', 'w', encoding='utf-8') as f:
    f.write(json.dumps(infos, ensure_ascii=False, indent=4, separators=(',', ':')))

結果截圖:
在這裏插入圖片描述
在這裏插入圖片描述

發佈了466 篇原創文章 · 獲贊 91 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章