前言

有个时候,我们需要做个ppt什么的,需要往ppt上插入背景图片,这个时候就要上网下载图片,今天我想到为什么不做个下载图片的小程序呢!


文章目录

  • 1.完成这个需要导入的模块
  • 1.2 第三方模块的安装
  • 2.怎样多线程爬取图片
  • 3.完整的代码
  • 4.总结


1.完成这个需要导入的模块

urllib,random,queue(队列),threading,time,os,json

1.2 第三方模块的安装

键盘win+R,输入cmd,来到命令窗口
对于urllib模块,安装代码pip install urllib3 ,

2.怎样多线程爬取图片

首先,我们需要来到这个网址
https://www.quanjing.com/ 然后输入关键字,来到另外一个界面,如 我输入 风景
多线程下载数据 python python多线程下载图片_下载图片
查看一下源代码,可以发现,这些图片的下载链接应该不是直接写在网址内的,我们点击鼠标右键,点击检查,点击Network,点击XHR,按F5刷新,可以发现XHR下面有这些图片的下载链接。
多线程下载数据 python python多线程下载图片_时间戳_02
这样我们就只需要这个网址就可以得到这一页所以图片的下载链接了。
https://www.quanjing.com/Handler/SearchUrl.ashx?t=8102&callback=searchresult&q=%E9%A3%8E%E6%99%AF&stype=1&pagesize=100&pagenum=1&imageType=2&imageColor=&brand=&imageSType=&fr=1&sortFlag=1&imageUType=&btype=&authid=&_=1584067448531
通过多个这样的网址进行分析可以发现,‘t=’后面的参数应该是一个四位的随机数,‘q=’后面的参数应该是自己输入图片的类型,也就是 风景,只不过这里对于它进行编码罢了,‘pagnum=’后面的参数是第几页的意思,网址中**‘pagesize=100’**标明煤业每页应该一百张图片,而总的页码数在这上有
多线程下载数据 python python多线程下载图片_时间戳_03
最后面的那个参数值应该是一个时间戳,通过处理得到的。
这样我们就可以得到爬取多页的图片了。
不过,进行爬取的时候,可以发现,就算得到了这个网址,也得不到这些数据,这个时候,我们可以来到这个网址的请求头那里,通过多次实验可以发现只需在请求头中加上:Referer:即可
这里为了让服务器认为我们是浏览器访问的,我们可以在请求头上添加:User-Agent
多线程下载数据 python python多线程下载图片_json_04
代码如下:

def get_time():  # 时间戳处理
    str_time = str(time.time())
    str_time = str_time[:str_time.find('.')] + str_time[str_time.find('.') + 1:str_time.find('.') + 4]
    time.sleep(1.25)  # 没得到一个时间戳,休眠1.25秒
    return str_time
def get_url():
    keyword = input('请输入你想下载的图片类型:')
    key_word = parse.urlencode({'q': keyword})
    num=int(input('请输入你想下载的图片数量:'))//100
    headers = {
        "Referer": "https://www.quanjing.com/search.aspx?%s" % (key_word),
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400"}
    url='https://www.quanjing.com/Handler/SearchUrl.ashx?t=%s&callback=searchresult&%s&stype=1&pagesize=100&pagenum=%s&imageType=2&imageColor=&brand=&imageSType=&fr=1&sortFlag=1&imageUType=&btype=&authid=&_=%s'

    list_url=[]
    for i in range(1,num+1):
        str_1 = str(random.random())
        random_1 = str_1[str_1.find('.') + 1:str_1.find('.') + 5]
        time_1=get_time()
        url_1=url%(random_1,key_word,i,time_1)
        list_url.append(url_1)

    return list_url,headers,keyword

通过这样我们就可以得到图片的下载链接了,后面只需多线程下载即可

不过,在多线程下载过程,发现下载的图片的数量远远低于自己输入的图片数量,其实这是因为图片同名的原因,我们可以在图片名称前面添加一个随机随机数即可;

运行:

多线程下载数据 python python多线程下载图片_时间戳_05


多线程下载数据 python python多线程下载图片_json_06


也许输入完成之后,会达不到自己输入的图片数量程序就自动结束了,建议多试几次。

完成之后,我们可以查看一下当前文件夹下面会多了一个文件夹,所下载的图片就在里面

多线程下载数据 python python多线程下载图片_下载图片_07


为了知道我们下载的图片的数量,我们可以这样:

import os
list_1=os.listdir('E:\Pycharm_1\爬虫\中国')
for i in range(len(list_1)):
    print(i+1,list_1[i])

运行结果:

多线程下载数据 python python多线程下载图片_下载图片_08


这样就发现这里有400张图片。

3.完整的代码

import urllib.parse as parse
from urllib import request
import random
from queue import Queue
import threading
import time
import json
import os



def get_time():  # 时间戳处理
    str_time = str(time.time())
    str_time = str_time[:str_time.find('.')] + str_time[str_time.find('.') + 1:str_time.find('.') + 4]
    time.sleep(1.25)  # 没得到一个时间戳,休眠1.25秒
    return str_time

def get_url():
    keyword = input('请输入你想下载的图片类型:')
    key_word = parse.urlencode({'q': keyword})
    num=int(input('请输入你想下载的图片数量:'))//100
    headers = {
        "Referer": "https://www.quanjing.com/search.aspx?%s" % (key_word),
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400"}
    url='https://www.quanjing.com/Handler/SearchUrl.ashx?t=%s&callback=searchresult&%s&stype=1&pagesize=100&pagenum=%s&imageType=2&imageColor=&brand=&imageSType=&fr=1&sortFlag=1&imageUType=&btype=&authid=&_=%s'

    list_url=[]
    for i in range(1,num+1):
        str_1 = str(random.random())
        random_1 = str_1[str_1.find('.') + 1:str_1.find('.') + 5]
        time_1=get_time()
        url_1=url%(random_1,key_word,i,time_1)
        list_url.append(url_1)

    return list_url,headers,keyword




tuple_1=get_url()
list_url,headers,keyword=tuple_1[0],tuple_1[1],tuple_1[2]
queue_url = Queue(len(list_url)*100+5)
queue_img = Queue(len(list_url)*100+5)

try:  # 防止因为没有该图片类型而报错
    num=1
    for i in range(len(list_url)):
        request_1=request.Request(url=list_url[i],headers=headers)
        content=request.urlopen(request_1)

        str_1 = content.read().decode('utf-8')  # 得到的数据字符串类型
        str_1 = str_1[str_1.find('(') + 1:str_1.rfind(')')]
        dict_1 = json.loads(str_1)
        images_list = dict_1['imglist']

        for j in range(len(images_list)):
            print('【{}】-{}'.format(num, images_list[j]['caption']))
            queue_url.put(images_list[j]['imgurl'])
            queue_img.put(images_list[j]['caption'])
            num+=1

    def Downlad(queue_url: Queue, queue_img: Queue):
        path_1 = './' + keyword
        try:
            os.mkdir(path_1)
        except:
            pass
        finally:
            while True:
                if queue_url.empty():
                    break
                image_name = queue_img.get()
                request.urlretrieve(url=queue_url.get(), filename=path_1 + '/【{}】-{}.png'.format(random.random()*1000,image_name))  # 下载图片
                # 为了防止出现图片名相同的情况,对于图片命名添加一个随机数
                print('线程{}正在下载【{}】'.format(threading.current_thread().getName(), image_name))
                time.sleep(0.25)  # 每下载一张图片,休眠0.25秒

    threading_list = []
    print('开始下载!')
    time.sleep(5)
    for i in range(len(list_url)*5):  # 根据用户的输入创建相应多的线程
        threading_1 = threading.Thread(target=Downlad, args=(queue_url, queue_img,))
        threading_1.start()
        threading_list.append(threading_1)

    for i in threading_list:
        i.join()

    print('------------------------下载完毕!当前线程为', threading.current_thread().getName())


except Exception as e:
    print(e,'没有搜到该图片或者今日访问次数过多!')

4.总结

1.这个代码还可以更新一下,如更换ip地址,这样应该就不会出现前面我说的那个问题了。
2.文章中语句没有表达清楚的,请大家多多包涵,我会慢慢改进的。
3.如果大家有什么好的建议,欢迎在下方留言,谢谢大家!