有趣的Python —— 圖片爬取(從分析到實現)

首先來個思維導圖。對這篇記錄有個大概認識。篇幅主要是記錄實現步驟,涉及的知識點在實現步驟中會體現,但不會展開細說。

大綱

1.分析網頁

1.1 分析url

要爬取的地址,鬥圖爲例:

第一頁:https://www.doutula.com/photo/list?page=1
第二頁:https://www.doutula.com/photo/list/?page=2

那麼,第N頁的url 地址就是 https://www.doutula.com/photo/list/?page= N

爲什麼 要分析url ,因爲爬取數據時候,不單單就爬取一頁的。設計出來的代碼,應該可以隨意爬取多少頁的數據的。或者自動爬取所有數據的。而通過分析爬取url 的變化規律,就可以輕鬆迭代所有的頁面了。

1.2 分析Html 結構,找出圖片鏈接

這裏就需要我們查找頁面的源代碼,進行分析了,找出需要的信息標籤。

A . 首先最好使用 Chrome瀏覽器 打開鬥圖網站,對應的頁面。

B . 然後我們按 F12,就會出現下面的界面:
Html 分析

C . 在源代碼中,先找到 body 標籤
body 標籤裏面就是網頁展示的源代碼

body

D. 在每個標籤上,移動鼠標,你發現有趣的事情,你鼠標停留在某個標籤上,左邊的頁面就會展示成藍色
標籤分析
E. 點擊打開標籤,一步步找到圖片所在的標籤
標籤分析

F. 最後我們看看每一張圖片的標籤代碼是長什麼樣的

第一個圖片標籤
<a class="col-xs-6 col-sm-3" href="https://www.doutula.com/photo/5489966" style="padding:5px;">
  <img 
    referrerpolicy="no-referrer" 
    src="//www.doutula.com/img/loader.gif" 
    style="width: 100%; height: 100%;" 
    data-original="http://ww3.sinaimg.cn/bmiddle/9150e4e5gy1g5aju5m3x8j206o06lwf1.jpg" 
    alt="小妹妹我的槍還不錯吧" 
    class="img-responsive lazy image_dta" 
    data-backup="http://img.doutula.com/production/uploads/image/2019/07/24/20190724948680_ObVYKx.png">
   <p style="display: none">小妹妹我的槍還不錯吧</p>
</a>

第二個圖片標籤
<a class="col-xs-6 col-sm-3" href="https://www.doutula.com/photo/7620638" style="padding:5px;">
   <img 
   referrerpolicy="no-referrer" 
   src="//www.doutula.com/img/loader.gif" 
   style="width: 100%; height: 100%;" 
   data-original="http://ww2.sinaimg.cn/bmiddle/9150e4e5gy1g5aju9zi9yj205g05i745.jpg" 
   alt="哼,氣死人家啦" 
   class="img-responsive lazy image_dta" 
   data-backup="http://img.doutula.com/production/uploads/image/2019/07/24/20190724948679_ynvITc.jpg">
   <p style="display: none">哼,氣死人家啦</p>
</a>

這是兩個 a 標籤, 標籤裏面包含了 <img 標籤 和 一個 <p 標籤。

img 標籤裏面就是我們需要找的信息,有三個重要信息:

1、圖片鏈接地址是:
   data-original=“http://ww3.sinaimg.cn/bmiddle/9150e4e5gy1g5aju5m3x8j206o06lwf1.jpg
2、圖片的名字是:
   alt=“小妹妹我的槍還不錯吧”

3、圖片標籤 <img 都一個特點是 class=“img-responsive lazy image_dta” , 這個信息非常重要,這個可以幫助我們找出所有的圖片標籤,因爲在鬥圖裏面,我們需要爬取的圖片標籤都有這個標識。

PS:同樣的步驟可以分析出其他網友的 Html 的結構,找到你需要的信息,進行爬取分析。
如果對Html 不瞭解或者想更深入瞭解的,可以自行查找Html 相關的知識,進行學習。


2.獲取網頁數據

上面都是分析部分,下面就要開始寫代碼了。
我們上面的分析都是通過網頁的源代碼進行的,這一步就是要獲取頁面的源代碼數據了。

這一步比較簡單,我們使用最原始的辦法 urllib 庫, 這個方法非常簡單, 返回的是網頁的 html 數據。

這裏的header 頭僞裝,這個比較重要,因爲你如果不設置header 頭,服務器會拒絕你的訪問,返回 403報錯

import urllib
import urllib.request

def get_web_html(url):
        """
        獲取需要爬取的html文件,做一定的瀏覽器僞裝
        :param url:地址
        :return: HTML結果
        """
        headers = {
            "User-Agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Mobile Safari/537.36"
        }
        request = urllib.request.Request(url = url, headers = headers)
        response = urllib.request.urlopen(request)
        return response.read()

PS. 對於動態數據的網頁, 這個方法是拿不到動態數據的, 可以使用 selenium 或者其他庫 進行模擬用戶行爲,打開網頁獲取網頁數據


3.使用BeautifulSoup4 獲取圖片鏈接

下載完網頁數據之後,就開始拿具體圖片數據了。

BeautifulSoup4 是非常好用的分析庫,可以快速的找到網頁裏面,我們需要的信息。
因爲是第三方庫,這個需要手動安裝一下:

pip install beautifulsoup4

下面的代碼就是根據我們第一步的分析,來獲取相關的圖片信息了:

from bs4 import BeautifulSoup

def get_pic_dic(html):
        """
        分析 Html 數據,獲取到圖片鏈接數據
        :param html: html源碼
        :return: 字典形式返回圖片鏈接數據  key : 圖片名字  value: 下載鏈接
        """ 
        soup = BeautifulSoup(html, features="lxml")
        matching = soup.body.find_all("img","img-responsive lazy image_dta")
        pic_dic = {}
        for pic_dot in matching:
            pic_dic.update({pic_dot["alt"]:pic_dot["data-original"]})
        return pic_dic

具體步驟分析:

1、soup = BeautifulSoup(html, features=“lxml”)
是獲取解析html的對象

2、matching = soup.body.find_all(“img”,“img-responsive lazy image_dta”)
這個就是我們第一步分析圖片標籤 class = “img-responsive lazy image_dta” 的作用,
這裏會在 body 裏面找到 class = “img-responsive lazy image_dta” 的所有的img標籤,以 列表的形式返回所有符合的標籤。

3、最後一個for 循環,就是把數據 塞到 一個字典裏面了。
第一步的分析,這裏就起作用了,字典 key 是 img 標籤裏面的 “alt” 屬性, 字典的value 就是 img 標籤的 “data-original”

這裏其實就是把第一步分析 img 標籤的事情, 代碼化了, 把數據提取出來


4. 進行圖片下載並保存

經過前面三步,分析,下載網頁,解析網頁,已經得到一堆 圖片鏈接了,下面就是把它下載到本地了。
先看看下載文件的代碼,也是一個函數,也非常簡單,這個是單個文件下載和寫入的函數:

# 步驟1
def download_file(url, file_name, extension, path_name = "download_file"):
    """
    下載文件(瀏覽器僞裝)
    :param url:下載地址
    :param file_name: 文件名稱
    :param extension: 後綴名稱
    :param path_name: 保存目錄
    :return: 保存目錄地址
    """
    
     # 步驟2
    headers = {
        "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Mobile Safari/537.36"
    }
    request = urllib.request.Request(url = url, headers= headers)
    response = urllib.request.urlopen(request)
    data = response.read()
    
    # 步驟3
    if path_name and not os.path.exists(path_name):
        os.mkdir(path_name)
    elif not path_name:
        path_name = "download_file"
        if not os.path.exists(path_name):
            os.mkdir(path_name)
        
    # 步驟4
    data_path = (path_name+'\%s' + extension) % file_name
    
    # 步驟5
    with open(data_path, 'wb') as file:
        file.write(data)

具體步驟分析:

1、 這個函數,傳入幾個參數:url (下載地址),file_name (下載後的文件名),extension (下載文件的後綴名), path_name (保存的目錄地址)
2、和網頁下載數據下載一樣,通過 urllib 庫,獲取圖片數據,這個可以和下載網頁複用
3、判斷需要保存的地址是否已經存在,如果不存在,就進行文件目錄的創建
4、組裝最後需要寫入的文件地址,如 : /doutu/哈哈哈.png
5、進入文件寫入


5. 最後組裝起來

先回顧一下,前面幾步:

第二步,是獲取單個url 頁面的數據;
第三步,是單個頁面解析,得到圖片鏈接字典;
第四步,是單個圖片文件下載;

這幾步都是單個,單個的, 我們最後應該是需要做些循環迭代,來獲取所有的數據。
第一步其實是有代碼的,就是循環迭代多個Url ,得到多個Url 的html 數據。然後繼續循環迭代獲取所有的圖片數據。

還是先來最後組裝成的代碼:

    #步驟1
    def begin_spider(pages):
        
        #步驟2
        for i in range(pages):
            print("page code:" , str(i+1), "start download")
           
            #步驟3
            html= get_web_html("https://www.doutula.com/photo/list?page=" + str(i+1))
           
            #步驟4
            pic_dic = get_pic_dic(html)
           
            #步驟5
            for key, pic in pic_dic.items():
                #步驟6
                pic_split_list = pic.split(".")
                extension_str = pic_split_list[len(pic_split_list) - 1]
                #步驟7
                download_file(pic, StringUtils.final_dic_name(key), "." + extension_str, path_name = "doutu")
                
            print("page code:", str(i+1),", Finish!")

具體步驟分析:
1、參數出入 pages ,需要爬取的頁數;
2、一個for 循環,進行頁面url迭代;
3、根據url 的規律,每個循環得到一個新的頁面url ,並且調用get_web_html 獲取單個 url 數據;
4、根據url 頁面數據,調用 get_pic_dic 獲取單頁面的 圖片 字典;
5、進行字典循環,獲取每一條圖片數據;
6、這是一個特殊操作,就是提取出 圖片的後綴名(因爲圖片後綴有可能是 多種的,如 png, jpeg, git 等)
7、調用前面的 download_file ,進行文件下載。 (代碼中 StringUtils.final_dic_name(key),這個是一個文件名的處理函數,正則實現,去掉非法的字符,不去掉的話,可能會出現寫不了文件的報錯)

就一句代碼:

import re
def final_dic_name(org_name):
   """
   :param org_name: 原始字符串
   :return: 合法字符串
   文件夾名稱處理,去除不合法字符
   """
   return re.sub(r'[\\/:*?<>|]',"",org_name)

最後調用 begin_spider ,輸入需要獲取的頁數,就可以獲取對應頁數的圖片數據了。

我爬了10頁數據, 672張圖片:
圖片


總結

按照步驟實現,基本可以實現鬥圖圖片的爬取了,代碼量其實非常少,這也是 Python 的優勢。

如果需要爬取其他網站(靜態網站),其實也是一樣的道理的,有些步驟是通用的,不過分析 url 和 解析html 數據的細節會不一樣。下載網頁,下載圖片這些代碼基本都是一樣的。可以拿個其他網站練習一下。

這裏描述的基本都是爬圖片的實現流程,但是其實裏面很多細節點,都是沒有展開的,如: Html 結構,BeautifulSoup4的更多用法,文件寫入,有興趣可以去認真學習一下。對做數據的爬取都非常有幫助的。

免責聲明:
本內容僅供學習使用,如用於違法行爲操作,與本人無關。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章