寫於 2018.01.24html
項目地址:github.com/jrainlau/wa…python
很久沒有寫文章了,由於最近都在適應新的崗位,以及利用閒暇時間學習python。這篇文章是最近的一個python學習階段性總結,開發了一個爬蟲批量下載某壁紙網站的高清壁紙。git
注意:本文所屬項目僅用於python學習,嚴禁做爲其餘用途使用!github
項目使用了virtualenv
來建立一個虛擬環境,避免污染全局。使用pip3
直接下載便可:瀏覽器
pip3 install virtualenv
複製代碼
而後在合適的地方新建一個wallpaper-downloader
目錄,使用virtualenv
建立名爲venv
的虛擬環境:bash
virtualenv venv
. venv/bin/activate
複製代碼
接下來建立依賴目錄:dom
echo bs4 lxml requests > requirements.txt
複製代碼
最後yun下載安裝依賴便可:ide
pip3 install -r requirements.txt
複製代碼
爲了簡單起見,咱們直接進入分類爲「aero」的壁紙列表頁:wallpaperswide.com/aero-deskto…函數
能夠看到,這一頁裏面一共有10張可供下載的壁紙。可是因爲這裏顯示的都是縮略圖,做爲壁紙來講清晰度是遠遠不夠的,因此咱們須要進入壁紙詳情頁,去找到高清的下載連接。從第一張壁紙點進去,能夠看到一個新的頁面:工具
由於我機器是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都對應着一個連接:
因此第一步,就是把這些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_start
和page_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
複製代碼
而後能夠看到下列輸出:
拿charles抓一下包,能夠看到腳本正在平穩地運行中:
此時,下載腳本已經開發完畢,終於不用擔憂壁紙荒啦!