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")

 

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