Python通過URL下載圖片時的中文、空格處理

對於如何從目標網站如何爬取數據不是本章將要描述的重點,有興趣的同學可以去其它博客尋找答案。

 

將我遇到的問題進行簡化:已經獲取到一些URL了,每個鏈接都是指向網站中的一個圖片,現在需要把這些圖片都下載下來。但是在下載一些圖片時,報錯了。因爲涉及到網絡通信和文件的讀寫,所以對這些容易發生錯誤的地方加了 try...except... 可以打印出具體遇到的錯誤。

 

1. 先看一下我挑出的url數據。文件保存時默認用的GBK編碼保存的。用Pycharm打開時發現有亂碼,並且提示用gbk編碼格式重新打開,reload後就顯示正常了。

creative_id,pack_id,template_id,app_name,category_id,img_url
1000073,232,1,com.finaccel.android,1272,http://shareitcpi.rqmob.com/creatives/2020-02-15/aqchkyedah582ebbc371d02464016e7aec89bda418__FILE_CM____FILE_CM480_720__.jpg
1000073,232,1,com.finaccel.android,1272,http://shareitcpi.rqmob.com/creatives/img/2020-02-25/compress-147033907-v26f5wvgps6yglv2z48i01hnenhvticb.jpg
1000446,234,54,com.indiaBulls,1272,http://shareitcpi.rqmob.com/creatives/img/2020-03-11/compress-2113000390-o8qmg04quw35ck7bdwv4uykzmzbbanfn.png
1000081,234,4,com.indiaBulls,1272,http://shareitcpi.rqmob.com/creatives/2020-02-17/rjdkwm9jwgStock Market game.jpg_1080px x 270px-_副本_副本.jpg
1000080,234,2,com.indiaBulls,1272,http://shareitcpi.rqmob.com/creatives/2020-02-17/snbu2nfehs微信圖片_20200216202007.png

2. 先看代碼

# -*- coding: utf-8 -*-
import csv
import os
from urllib.request import urlretrieve
import urllib.parse
import string

img_url_file = 'img_url_temp.csv'
img_save_path = './img_data'
os.makedirs(img_save_path, exist_ok=True)
i = 0

with open(img_url_file, encoding='gbk') as csvfile:
    csv_reader = csv.reader(csvfile)
    birth_header = next(csv_reader)
    print(birth_header, "\n")  # ['creative_id', 'pack_id', 'template_id', 'app_name', 'category_id', 'img_url']
    print("======================")
    for row_list in csv_reader:
        try:
            img_url = row_list[5]
            # img_url = urllib.parse.quote(img_url, safe=string.printable).replace(" ", "%20")
            urlretrieve(img_url, 'img_data/'+str(row_list[0])+'#'+str(row_list[1])+'#'+str(row_list[2])+'#'+str(row_list[3])+'#'+str(row_list[4])+'#'+'.jpg')
        except Exception as e:
            print("error:", e)
            print("error_load_img:", img_url)
            print(row_list)
            i += 1
            print("+++++++++++++++++")

print("Error number: ", i)

不得不說,使用urlretrieve(url, filename) 可以很方便的將指定鏈接的圖片下載到指定位置,簡直是傻瓜式操作。

 

3. 錯誤處理

通過打印異常,可以看到有兩個錯誤:

a. url中不能包含控制字符

b. url只支持ascii碼值

"E:\Program Files\Python374\python.exe" F:/my_workspace/py_workspace/load_material_photo1.py
['creative_id', 'pack_id', 'template_id', 'app_name', 'category_id', 'img_url'] 

======================
error: URL can't contain control characters. '/creatives/2020-02-17/rjdkwm9jwgStock Market game.jpg_1080px x 270px-_副本_副本.jpg' (found at least ' ')
error_load_img: http://shareitcpi.rqmob.com/creatives/2020-02-17/rjdkwm9jwgStock Market game.jpg_1080px x 270px-_副本_副本.jpg
['1000081', '234', '4', 'com.indiaBulls', '1272', 'http://shareitcpi.rqmob.com/creatives/2020-02-17/rjdkwm9jwgStock Market game.jpg_1080px x 270px-_副本_副本.jpg']
+++++++++++++++++
error: 'ascii' codec can't encode characters in position 36-39: ordinal not in range(128)
error_load_img: http://shareitcpi.rqmob.com/creatives/2020-02-17/snbu2nfehs微信圖片_20200216202007.png
['1000080', '234', '2', 'com.indiaBulls', '1272', 'http://shareitcpi.rqmob.com/creatives/2020-02-17/snbu2nfehs微信圖片_20200216202007.png']
+++++++++++++++++
Error number:  2

總結來說就是,我的url中包含ascii的控制字符和中文,直接的導致了error。

順便說一句,ASCII碼其實是包含控制字符和可打印字符,一共128個,控制字符是不能打印出來的。

可以使用

urllib.parse.quote(url)

來對url中的特殊字符進行url的encode,根據某個RFC的定義,會把其中的中文和特殊字符都編碼爲%XX的格式,用%帶兩個十六進制數代表一個字符,如果是一個漢字需要3個%XX來表示。因爲encode時,使用的utf-8編碼,在utf-8中一個漢字佔了三個字節,和Unicode中每個漢字佔兩個字節還是非常不同的。

既然是大家都公認的RFC文檔中定義的,那麼將編碼後的rul字符串直接copy到瀏覽器中應該也是可以訪問的。

http://shareitcpi.rqmob.com/creatives/2020-02-17/rjdkwm9jwgStock Market game.jpg_1080px x 270px-_副本_副本.jpg
->
http%3A//shareitcpi.rqmob.com/creatives/2020-02-17/rjdkwm9jwgStock%20Market%20game.jpg_1080px%20x%20270px-_%E5%89%AF%E6%9C%AC_%E5%89%AF%E6%9C%AC.jpg

但是發現http後面的冒號也被編碼爲%3A了,這時瀏覽器肯定是不認了。其實如果只保留http://後面的uri,瀏覽器也是認的,可以自動給添加http://。但是我們的urlretrieve()函數還不行。

這裏想到兩個解決辦法:

a. quote(url)前先把url前面的http://或https://去掉,在結束後給拼接回去。

b. 在quote(url)中使用參數

safe=string.printable

這樣就只會替換中文,像冒號這種字符就不會被替換了,畢竟冒號屬於可打印字符。新的問題就出現了,空格也屬於可打印字符,但是url是不認它的。需要再專門把空格替換爲%20。最後就多加一句

img_url = urllib.parse.quote(img_url, safe=string.printable).replace(" ", "%20")

 

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