17-多线程爬虫-实战多线程下载王者荣耀高清壁纸

实战多线程下载王者荣耀高清壁纸
1.网址:https://pvp.qq.com/web201605/wallpaper.shtml

2.查看网页源代码,发现腾讯将相关图片url信息转换成注释信息,猜测可能通过json动态添加,从Network找到存储高清壁纸文件(发现图片是用url编码的,需要用urllib.parse对获取到的url进行解码)

高清壁纸真实图片网址(workList_inc.cgi?) https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=0&iOrder=0&iSortNumClose=1&jsoncallback=jQuery171018799755464476742_1619442228146&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1619442228321

3.通过上面的json文件,获取到高清壁纸的url

4.获取到高清壁纸的url后,通过parse.unquote可以进行解码,然后将最后的/200变成/0,就可以得到真实的高清壁纸的图片了

5.获取图片的url的地址中有一个page参数,通过修改page的值,可以进行翻页。默认page是从0开始的

6.page最多只有25页,因此区间是[0,24]

 

一、实战多线程下载王者荣耀高清壁纸(单线程)

# 1.实战多线程下载王者荣耀高清壁纸(单线程)

import requests
from fake_useragent import UserAgent
from urllib import parse
import json
import os

user_agent = UserAgent()
headers = {
    "User-Agent":user_agent.chrome,
    "referer":"https://pvp.qq.com/"
}

# 定义一个从右往左的rreplace替换函数
def rreplace(self, old, new, *max):
    count = len(self)
    if max and str(max[0]).isdigit():
        count = max[0]
    return new.join(self.rsplit(old, count))

# 提取图片的url,并进行处理
def extract_images(data):
    image_urls = []
    
    # 获取data里每个对象对应的八个高清壁纸url(需要用urllib.parse对获取到的url进行解码,并将/200转换为/0)
    for x in range(1,9):
        image_url = parse.unquote(data["sProdImgNo_{}".format(x)])
        # 调用rreplace,从右向左进行替换将/200转换为/0
        image_url = rreplace(image_url,"/200","/0",1)
        image_urls.append(image_url)
    return image_urls

def main():
    # 在程序开始前,获取F:\爬虫\第五章-多线程爬虫实战\images目录下所有文件夹名称,存储在列表中
    name_list = os.listdir("F:\爬虫\第五章-多线程爬虫实战\images")
    print("请输入当前目录下,已经存在的王者荣耀高清皮肤文件夹:\n",name_list)
    
    # 高清壁纸真实图片网址
    page = int(input("请输入要爬取的王者荣耀壁纸的第几页:"))-1
    page_url = "https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page={}&iOrder=0&iSortNumClose=1&jsoncallback=jQuery171020290982002904112_1612592073295&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1612592073509".format(page)

    # 通过requests获取到json对象,获取url
    resp = requests.get(page_url,headers=headers)
    content = resp.content.decode("utf-8")
    # print(content)
    
    # 对获取到的cotent进行处理,去除前面的jQuery171036102371408234957_1612523399971()函数
    index_1 = content.find("(") 
    index_2 = content.find(")") 
    content = content[index_1+1:index_2]
    # print(type(content))
    
    # 利用json库,将python对象转化为json字符串(str -> 字典)
    # import json
    result = json.loads(content)
    # print(type(result))
    
    # 获取result字典里面key为List的值(存放着对应皮肤的名字和图片)
    datas = result["List"]
    # 当前页面的每个皮肤名字,用列表存储
    names = []
    num = 1
    for data in datas:
        
        # 调用,提取图片的url并进行处理
        image_urls = extract_images(data)
        # 获取皮肤的名字(注意有些特殊符号,不能作为文件夹名字)
        name = parse.unquote(data["sProdName"]).replace("·", "-").replace(":", "-").strip()
        # print(name,image_urls)
        
        # 针对当前页面,有重复的名字,进行处理如澜CG《目标》2
        if name not in names:
            names.append(name)
        else:
            num += 1
            name = name+str(num)
            names.append(name)
        
        # 判断name是否在name_list,再决定是否创建
        if name not in name_list:
            # 利用os库,在F:/爬虫/第五章-多线程爬虫实战/images创建文件夹,名字为name
            # import os
            path = "F:\爬虫\第五章-多线程爬虫实战\images"
            # 创建文件夹
            path_name = os.path.join(path,name)
            os.mkdir(path_name)
            print("创建文件夹{}成功!".format(name))

            # 在相应的文件夹中,创建图片文件,enumerate()同时返回数据下标和数据
            for index,image_url in enumerate(image_urls):
                path_img = os.path.join(path_name,"{}.jpg".format(index+1))
                # 下载文件,图片要以wb二进制的方式写入
                with open(path_img,"wb") as f:
                    # response.content返回的是bytes类型
                    content_img = requests.get(image_url,headers=headers).content
                    f.write(content_img)
                    print("正在写入高清壁纸{}...".format(path_img))
    

if __name__ == "__main__":
    main()

二、实战多线程下载王者荣耀高清壁纸(多线程)

# 2.实战多线程下载王者荣耀高清壁纸(多线程)

import requests
from fake_useragent import UserAgent
from urllib import parse
import json
import os
import threading
import queue

user_agent = UserAgent()
headers = {
    "User-Agent":user_agent.chrome,
    "referer":"https://pvp.qq.com/"
}

# 生产者(获取队列中每一个page_url,已经创建皮肤名字的文件夹)
class Producer(threading.Thread):
    def __init__(self,page_queue,image_queue,name_list,*args,**kwargs):
        # 调用父类的__init__函数
        super(Producer,self).__init__(*args,**kwargs)
        
        self.page_queue = page_queue
        self.image_queue = image_queue
        self.name_list = name_list
    
    def run(self) -> None:
        # 当前线程的对象
        the_thread = threading.current_thread()
        
        # 当page_queue队列不为空时,一直循环
        while not self.page_queue.empty():
            # 从队列中取出page_url
            page_url = self.page_queue.get()
            name_list = self.name_list
            
            # 通过requests获取到json对象,获取url
            resp = requests.get(page_url,headers=headers)
            content = resp.content.decode("utf-8")
            # print(content)

            # 对获取到的cotent进行处理,去除前面的jQuery171036102371408234957_1612523399971()函数
            index_1 = content.find("(") 
            index_2 = content.find(")") 
            content = content[index_1+1:index_2]
            # print(type(content))

            # 利用json库,将python对象转化为json字符串(str -> 字典)
            # import json
            result = json.loads(content)
            # print(type(result))

            # 获取result字典里面key为List的值(存放着对应皮肤的名字和图片)
            datas = result["List"]
            # 当前页面的每个皮肤名字,用列表存储
            names = []
            num = 1
            for data in datas:

                # 调用,提取图片的url并进行处理
                image_urls = extract_images(data)
                # 获取皮肤的名字(注意有些特殊符号,不能作为文件夹名字)
                name = parse.unquote(data["sProdName"]).replace("·", "-").replace(":", "-").strip()
                # print(name,image_urls)

                # 针对当前页面,有重复的名字,进行处理如澜CG《目标》2
                if name not in names:
                    names.append(name)
                else:
                    num += 1
                    name = name+str(num)
                    names.append(name)

                # 判断name是否在name_list,再决定是否创建
                if name not in name_list:
                    # 利用os库,在F:/爬虫/第五章-多线程爬虫实战/images2创建文件夹,名字为name
                    # import os
                    path = "F:\爬虫\第五章-多线程爬虫实战\images2"
                    # 创建文件夹
                    path_name = os.path.join(path,name)
                    os.mkdir(path_name)
                    print("当前线程{0}\t创建文件夹{1}成功!".format(the_thread.name,name))
                    
                    # 将图片对应的image_url放入到image_queue队列中(字典类型,不仅传入image_url,还传入文件名)
                    for index,image_url in enumerate(image_urls):
                        image_path = os.path.join(path_name,"{}.jpg".format(index+1))
                        self.image_queue.put({"image_url":image_url,"image_path":image_path})
                    
    
# 消费者(将王者荣耀高清壁纸下载)
class Consumer(threading.Thread):
    def __init__(self,image_queue,*args,**kwargs):
        # 调用父类的__init__函数
        super(Consumer,self).__init__(*args,**kwargs)
        
        self.image_queue = image_queue
    
    def run(self) -> None:
        # 当前线程的对象
        the_thread = threading.current_thread()
        
        # 因为消费者和生产者进程同时开始,但由于生产者需要访问页面,导致消费者进程的img_queue队列一开始就是空的,需要一直循环执行
        while True:
            try:
                # 获取图片对象,字典{"image_url":image_url,"image_path":image_path}
                # timeout = 10指的是img_queue队列十秒钟一直处于阻塞状态,抛出异常(当队列为空时,还进行get()操作,进程会发生阻塞)
                image_obj = self.image_queue.get(timeout = 10)
                image_url = image_obj.get("image_url")
                image_path = image_obj.get("image_path")
                # 下载文件,图片要以wb二进制的方式写入
                with open(image_path,"wb") as f:
                    # response.content返回的是bytes类型
                    content_img = requests.get(image_url,headers=headers).content
                    f.write(content_img)
                    print("当前线程{0}\t正在写入高清壁纸{1}...".format(the_thread.name,image_path))
            except:
                # 获取到进程发生的异常,一般是生产者不再产生数据,消费者无法从空的img_queue队列获取数据
                break

# 定义一个从右往左的rreplace替换函数
def rreplace(self, old, new, *max):
    count = len(self)
    if max and str(max[0]).isdigit():
        count = max[0]
    return new.join(self.rsplit(old, count))

# 提取图片的url,并进行处理
def extract_images(data):
    image_urls = []
    
    # 获取data里每个对象对应的八个高清壁纸url(需要用urllib.parse对获取到的url进行解码,并将/200转换为/0)
    for x in range(1,9):
        image_url = parse.unquote(data["sProdImgNo_{}".format(x)])
        # 调用rreplace,从右向左进行替换将/200转换为/0
        image_url = rreplace(image_url,"/200","/0",1)
        image_urls.append(image_url)
    return image_urls

def main():
    # 在程序开始前,获取F:\爬虫\第五章-多线程爬虫实战\images2目录下所有文件夹名称,存储在列表中
    name_list = os.listdir("F:\爬虫\第五章-多线程爬虫实战\images2")
    print("请输入当前目录下,已经存在的王者荣耀高清皮肤文件夹:\n",name_list)
    
    # 高清壁纸真实图片网址
    page = int(input("请输入要爬取的王者荣耀壁纸的前几页:"))
    
    # 创建一个页面队列对象,大小为page(先进先出)
    page_queue = queue.Queue(page)
    # 创建一个图片队列对象,默认大小大一点(先进先出)
    image_queue = queue.Queue(1000)
    
    for x in range(page):
        page_url = "https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page={}&iOrder=0&iSortNumClose=1&jsoncallback=jQuery171020290982002904112_1612592073295&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1612592073509".format(x)
        # 往队列里放入page_url
        page_queue.put(page_url)
        
     # 创建三个生产者进程
    for x in range(3):
        th = Producer(page_queue,image_queue,name_list,name="生产者{}".format(x+1))
        th.start()
    
    # 创建三个消费者进程
    for x in range(3):
        th = Consumer(image_queue,name="消费者{}".format(x+1))
        th.start()

if __name__ == "__main__":
    main()

 

posted @ 2021-04-26 21:43  马铃薯1  阅读(175)  评论(0编辑  收藏  举报