70 行 python 程式碼實現桌布批量下載

Jrain發表於2019-01-30

寫於 2018.01.24

專案地址:github.com/jrainlau/wa…

前言

好久沒有寫文章了,因為最近都在適應新的崗位,以及利用閒暇時間學習python。這篇文章是最近的一個python學習階段性總結,開發了一個爬蟲批量下載某桌布網站的高清桌布。

注意:本文所屬專案僅用於python學習,嚴禁作為其他用途使用!

初始化專案

專案使用了virtualenv來建立一個虛擬環境,避免汙染全域性。使用pip3直接下載即可:

pip3 install virtualenv
複製程式碼

然後在合適的地方新建一個wallpaper-downloader目錄,使用virtualenv建立名為venv的虛擬環境:

virtualenv venv

. venv/bin/activate
複製程式碼

接下來建立依賴目錄:

echo bs4 lxml requests > requirements.txt
複製程式碼

最後yun下載安裝依賴即可:

pip3 install -r requirements.txt
複製程式碼

分析爬蟲工作步驟

為了簡單起見,我們直接進入分類為“aero”的桌布列表頁:wallpaperswide.com/aero-deskto…

70 行 python 程式碼實現桌布批量下載

可以看到,這一頁裡面一共有10張可供下載的桌布。但是由於這裡顯示的都是縮圖,作為桌布來說清晰度是遠遠不夠的,所以我們需要進入桌布詳情頁,去找到高清的下載連結。從第一張桌布點進去,可以看到一個新的頁面:

70 行 python 程式碼實現桌布批量下載

因為我機器是Retina螢幕,所以我打算直接下載體積最大的那個以保證高清(紅圈所示體積)。

瞭解了具體的步驟以後,就是通過開發者工具找到對應的dom節點,提取相應的url即可,這個過程就不再展開了,讀者自行嘗試即可,下面進入編碼部分。

訪問頁面

新建一個download.py檔案,然後引入兩個庫:

from bs4 import BeautifulSoup
import requests
複製程式碼

接下來,編寫一個專門用於訪問url,然後返回頁面html的函式:

def visit_page(url):
    headers = {
      'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36'
    }
    r = requests.get(url, headers = headers)
    r.encoding = 'utf-8'
    return BeautifulSoup(r.text, 'lxml')
複製程式碼

為了防止被網站反爬機制擊中,所以我們需要通過在header新增UA把爬蟲偽裝成正常的瀏覽器,然後指定utf-8編碼,最後返回字串格式的html。

提取連結

在獲取了頁面的html以後,就需要提取這個頁面桌布列表所對應的url了:

def get_paper_link(page):
    links = page.select('#content > div > ul > li > div > div a')
    return [link.get('href') for link in links]
複製程式碼

這個函式會把列表頁所有桌布詳情的url給提取出來。

下載桌布

有了詳情頁的地址以後,我們就可以進去挑選合適的size了。在對頁面的dom結構分析後可以知道,每一個size都對應著一個連結:

70 行 python 程式碼實現桌布批量下載

所以第一步,就是把這些size對應的連結提取出來:

wallpaper_source = visit_page(link)
wallpaper_size_links = wallpaper_source.select('#wallpaper-resolutions > a')
size_list = [{
    'size': eval(link.get_text().replace('x', '*')),
    'name': link.get('href').replace('/download/', ''),
    'url': link.get('href')
} for link in wallpaper_size_links]
複製程式碼

size_list就是這些連結的一個集合。為了方便接下來選出最高清(體積最大)的桌布,在size中我使用了eval方法,直接把這裡的5120x3200給計算出來,作為size的值。

獲取了所有的集合之後,就可以使用max()方法選出最高清的一項出來了:

biggest_one = max(size_list, key = lambda item: item['size'])
複製程式碼

這個biggest_one當中的url就是對應size的下載連結,接下來只需要通過requests庫把連結的資源下載下來即可:

result = requests.get(PAGE_DOMAIN + biggest_one['url'])

if result.status_code == 200:
    open('wallpapers/' + biggest_one['name'], 'wb').write(result.content)
複製程式碼

注意,首先你需要在根目錄下建立一個wallpapers目錄,否則執行時會報錯。

整理一下,完整的download_wallpaper函式長這樣:

def download_wallpaper(link):
    wallpaper_source = visit_page(PAGE_DOMAIN + link)
    wallpaper_size_links = wallpaper_source.select('#wallpaper-resolutions > a')
    size_list = [{
        'size': eval(link.get_text().replace('x', '*')),
        'name': link.get('href').replace('/download/', ''),
        'url': link.get('href')
    } for link in wallpaper_size_links]

    biggest_one = max(size_list, key = lambda item: item['size'])
    print('Downloading the ' + str(index + 1) + '/' + str(total) + ' wallpaper: ' + biggest_one['name'])
    result = requests.get(PAGE_DOMAIN + biggest_one['url'])

    if result.status_code == 200:
        open('wallpapers/' + biggest_one['name'], 'wb').write(result.content)
複製程式碼

批量執行

上述的步驟僅僅能夠下載第一個桌布列表頁第一張桌布。如果我們想下載多個列表頁全部桌布,我們就需要迴圈呼叫這些方法。首先我們定義幾個常量:

import sys

if len(sys.argv) != 4:
    print('3 arguments were required but only find ' + str(len(sys.argv) - 1) + '!')
    exit()

category = sys.argv[1]

try:
    page_start = [int(sys.argv[2])]
    page_end = int(sys.argv[3])
except:
    print('The second and third arguments must be a number but not a string!')
    exit()
複製程式碼

這裡通過獲取命令列引數,指定了三個常量category, page_startpage_end,分別對應著桌布分類,起始頁頁碼,終止頁頁碼。

為了方便起見,再定義兩個url相關的常量:

PAGE_DOMAIN = 'http://wallpaperswide.com'
PAGE_URL = 'http://wallpaperswide.com/' + category + '-desktop-wallpapers/page/'
複製程式碼

接下來就可以愉快地進行批量操作了,在此之前我們來定義一個start()啟動函式:

def start():
    if page_start[0] <= page_end:
        print('Preparing to download the ' + str(page_start[0])  + ' page of all the "' + category + '" wallpapers...')
        PAGE_SOURCE = visit_page(PAGE_URL + str(page_start[0]))
        WALLPAPER_LINKS = get_paper_link(PAGE_SOURCE)
        page_start[0] = page_start[0] + 1

        for index, link in enumerate(WALLPAPER_LINKS):
            download_wallpaper(link, index, len(WALLPAPER_LINKS), start)
複製程式碼

然後把之前的download_wallpaper函式再改寫一下:

def download_wallpaper(link, index, total, callback):
    wallpaper_source = visit_page(PAGE_DOMAIN + link)
    wallpaper_size_links = wallpaper_source.select('#wallpaper-resolutions > a')
    size_list = [{
        'size': eval(link.get_text().replace('x', '*')),
        'name': link.get('href').replace('/download/', ''),
        'url': link.get('href')
    } for link in wallpaper_size_links]

    biggest_one = max(size_list, key = lambda item: item['size'])
    print('Downloading the ' + str(index + 1) + '/' + str(total) + ' wallpaper: ' + biggest_one['name'])
    result = requests.get(PAGE_DOMAIN + biggest_one['url'])

    if result.status_code == 200:
        open('wallpapers/' + biggest_one['name'], 'wb').write(result.content)

    if index + 1 == total:
        print('Download completed!\n\n')
        callback()
複製程式碼

最後指定一下啟動規則:

if __name__ == '__main__':
     start()

複製程式碼

執行專案

在命令列輸入如下程式碼開始測試:

python3 download.py aero 1 2
複製程式碼

然後可以看到下列輸出:

70 行 python 程式碼實現桌布批量下載

拿charles抓一下包,可以看到指令碼正在平穩地執行中:

70 行 python 程式碼實現桌布批量下載

此時,下載指令碼已經開發完畢,終於不用擔心桌布荒啦!

相關文章