Python下載網絡圖片方法彙總與實現

本文介紹下載python下載網絡圖片的方法,包括經過圖片url直接下載、經過re/beautifulSoup解析html下載以及對動態網頁的處理等。html

經過pic_url單個/批量下載

已知圖片url,例如http://xyz.com/series-*(1,2..N).jpg,共N張圖片,其連接形式較爲固定,這樣經簡單循環,直接經過`f.write(requests.get(url).content)'便可以二進制形式將圖片寫入。python

import os
import requests

def download(file_path, picture_url):
	headers = {
		"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE",
		}
	r = requests.get(picture_url, headers=headers)
	with open(file_path, 'wb') as f:
		f.write(r.content)

def main():
	os.makedirs('./pic/', exist_ok=True)  # 輸出目錄

	prefix_url = 'http://xyz.com/series-'  # 同一類目下的圖片url前綴
	n = 6  # 該類目下的圖片總數

	tmp = prefix_url.split('/')[-1]
	for i in range(1, n + 1):
		file_path = './pic/' + tmp + str(i) + '.jpg'
		picture_url = prefix_url + str(i) + '.jpg'
		download(file_path, picture_url)
		

if __name__ == '__main__':
	main()
複製代碼

正則re解析html獲取pic_url後下載

在實際操做中,圖片url按序排列狀況較少,多數狀況下用戶僅知道網頁url,須要對當前網頁htnl內容進行解析,獲取源碼中包含的圖片url,經常使用方法有正則表達式匹配或BeautifulSoup等庫解析的方法。git

正則re解析的思路是:首先經過requests.get(url).text得到當前頁面html源碼;而後經過正則表達式匹配圖片url,如re.compile(r'[a-zA-z]+://[^\s]*\.jpg') 正則式通常會獲得.jpg結尾的url,但其餘網站圖片url可能會以.png或.webp等結尾,甚至須要其餘的正則匹配,爲此,讀者須要對正則表達式有所瞭解,強烈推薦正則表達式30分鐘入門教程;將前一步獲得的圖片url加入列表,進行下載。github

import os
import re
import requests

def get_html(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 ",
        }
    html = requests.get(url, headers=headers).text

    return html

def parse_html(html_text):
    picre = re.compile(r'[a-zA-z]+://[^\s]*\.jpg')  # 本正則式獲得.jpg結尾的url
    pic_list = re.findall(picre, html_text)

    return pic_list

def download(file_path, pic_url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 ",
        }
    r = requests.get(pic_url, headers=headers)
    with open(file_path, 'wb') as f:
        f.write(r.content)

def main():
    # 使用時修改url便可
    url = 'http://xyz.com/series'
    html_text = get_html(url)
    pic_list = parse_html(html_text)

    os.makedirs('./pic/', exist_ok=True)  # 輸出目錄
    for pic_url in pic_list:
        file_name = pic_url.split('/')[-1]
        file_path = './pic/' + file_name

        download(file_path, pic_url)


if __name__ == '__main__':
    main()
複製代碼

經過bs4獲取pic_url

與正則匹配思路相似,只不過經過Beautiful Soup解析html得到圖片url列表,而後依次下載圖片。因爲各網站html結構有差別,用戶須要自行進行適當修改。如下代碼是對豆瓣圖片的下載。web

import os
import time
import requests
from bs4 import BeautifulSoup

def get_html(url):
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
    }
    html = requests.get(url, headers=headers).text

    return html

def parse_html(html_text):
    soup = BeautifulSoup(html_text, 'html.parser')
    li = soup.find_all('div', attrs={'class':'cover'})

    pic_list = []
    for link in li:
        pic_url = link.find('img').get('src')
        pic_url = pic_url.replace('/m/', '/l/')
        pic_list.append(pic_url)

    return pic_list

def download(file_path, pic_url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 ",
        }
    r = requests.get(pic_url, headers=headers)
    with open(file_path, 'wb') as f:
        f.write(r.content)

def main():
    '從豆瓣下載石原里美圖片,觀察發現每頁包含30張圖片,其url按30遞增,以下所示'
    pic_list = []
    for i in range(10):
        url = 'https://movie.douban.com/celebrity/1016930/photos/?type=C&start=' + str(30*i) + '&sortby=like&size=a&subtype=a'
        html_text = get_html(url)
        pic_list += parse_html(html_text)
        
    os.makedirs('./pic/', exist_ok=True)  # 輸出目錄

    for i, pic_url in enumerate(pic_list):
        if i%30 == 0:
            print('正在下載第%s頁'%(i/30+1))
        file_name = pic_url.split('/')[-1].split('.')[0] + '.jpg'
        file_path = './pic/' + file_name

        download(file_path, pic_url)


if __name__ == '__main__':
    main()
複製代碼

在下載圖片時,發現能夠直接訪問圖片的縮略圖url進行下載,但因爲豆瓣的反爬策略,直接訪問原圖url會被服務器拒絕,見下圖。解決方法見下一部分。ajax

可能遇到的問題

  • 網站反爬蟲機制正則表達式

    1. User-Agent:模擬瀏覽器訪問,添加後,服務器會認爲是瀏覽器正常的請求。通常與網頁操做相關訪問都予以添加。
    2. Referer:瀏覽器以此來判斷你從哪個網頁跳轉過來。例如在上述豆瓣圖片的下載示例中,直接輸入網址會被拒絕,但你在網站一步步點擊卻會在同一地址中獲得內容,這就是由於你在一步步訪問時是有一個前序跳轉地址的,這個地址能夠經過「F12」在header中獲得,若是找不到的話試一試根目錄地址「movie.douban.com/」,或是前幾步的地址」…GitHub倉庫’adv_bs4_url.py‘文件
    3. ip假裝:構建ip池。
    4. Cookie假裝:cookie是服務器用來辨別你此時的狀態的,每一次向服務器請求cookie都會隨之更新。
  • 經常使用正則式匹配瀏覽器

  • 網頁的數據採用異步加載,如js渲染的頁面或ajax加載的數據經過get不到完整頁面源碼。服務器

    • 一種方案是常說的動態爬蟲,即採用一些第三方的工具,模擬瀏覽器的行爲加載數據,如Selenium、PhantomJs等。網絡上有較多介紹文章,有點麻煩就沒有本身寫了,後續有需求的話在作吧,不過其餘方法已經夠用了。cookie

    • 另外能夠經過分析頁面,找到請求借口,加載頁面。其核心就是跟蹤頁面的交互行爲 JS 觸發調度,分析出有價值、有意義的核心調用(通常都是經過 JS 發起一個 HTTP 請求),而後咱們使用 Python 直接訪問逆向到的連接獲取價值數據。經過"F12」進行分析,例如對於花瓣網,能夠得到其連接爲"huaban.com/search/?q=石…request.urlopen(url).read()讀取網頁。

  • 其餘問題...

Pyautogui,鼠標模擬點擊的「傻瓜式」流程

本方法僅適用於重複性的工做,並且效率較低,但徹底沒有被反爬蟲策略屏蔽的風險。其核心思想與word中的「宏」相似,就是你告訴計算機一次循環中鼠標分別如何操做,而後讓其自動循環。代碼簡單明瞭。

import pyautogui
import time

pyautogui.FAILSAFE = True

def get_mouse_positon():
    time.sleep(3)  # 此間將鼠標移動到初始位置
    x1, y1 = pyautogui.position()
    print(x1, y1)
    pyautogui.click(x=x1, y=y1, button='right')  # 模擬鼠標右鍵點擊,呼出菜單
    time.sleep(5)  # 此間將鼠標移動到「save image as...」選項中央
    x2, y2 = pyautogui.position()
    print(x2, y2)
    pyautogui.click(x=x2, y=y2)  # 模擬鼠標左鍵點擊,點中「save image as...」
    time.sleep(10)  # 此間彈出保存文件彈窗,自行選擇保存位置,並將鼠標移至「保存(S)」按鈕中央
    x3, y3 = pyautogui.position()
    pyautogui.click(x=x3, y=y3)
    print(x3, y3)


def click_download(N):
    for i in range(N):  # 擬下載圖片數量
        pyautogui.click(x=517, y=557, duration=0.25, button='right')  # 呼出菜單,自行將x/y設置爲x1/y1
        time.sleep(1)
        pyautogui.click(x=664, y=773, duration=0.25)  # 下載,x/y爲x2/y2
        time.sleep(1)
        pyautogui.click(x=745, y=559, duration=0.25)  # 保存,x/y爲x3/y3
        time.sleep(1)
        pyautogui.click(x=517, y=557, duration=0.25)  # 進入下一張圖片
        time.sleep(2) # 取決於網絡加載速度,自行設置
    
 
 
if __name__ == "__main__":
    # get_mouse_positon() # 一開始只運行此命令,獲取屏幕座標,後續註釋掉該句
    click_download(10)
複製代碼

文中所有代碼、詳細註釋及更新見Github倉庫

相關文章
相關標籤/搜索