Python-爬虫基础:基于 urllib 爬取电脑壁纸

记忆云壁纸爬取

网址:https://zvvx.cn/one/bizhi/

前言:

加油!我们都是追梦人!

本篇文章将会基于 urllib 中的request 库进行爬取,会使用 json 进行数据的序列化操作,同时也会在最后举出两种下载方式 其中会使用到 threading 线程库。

# 导入 urllib
from urllib import request
import json
import threading
首先在浏览器中找到数据接口

接口图片

然后找到接口的传参规则

url = https://zvvx.cn/one/bizhi/api.php?cid=36&start=0&count=30
cid=6 分类
start=0 开始位置
count=30 张数 实测最多200张有数据,超过200张没有数据

需求:

用户输入下载的种类,下载的张数,进行下载

第一步:获得图片分类

获取所有图片分类的 cid

class_dict = {
    "4K专区": 36,
    "美女模特": 6,
    "爱情美图": 30,
    "风景大片": 9,
    "小清新": 15,
    "动漫卡通": 26,
    "明星风尚": 11,
    "萌宠动物": 14,
    "游戏壁纸": 5,
    "汽车天下": 12,
    "炫酷时尚": 10,
    "月历壁纸": 29,
    "影视剧照": 7,
    "节日美图": 13,
    "军事天地": 22,
    "劲爆体育": 16,
    "BABY秀": 18,
    "文字控": 35
    }

第二步:交互

输出图片分类供用户选择,并接受用户的输入

# 向屏幕输出图片分类信息
print("以下分类请选择:")
for c in class_dict:
    print(c, class_dict[c])
# 用户输入参数以下载
input_cid = int(input("请输入你要下载的分类[输入数字]:"))
input_count = int(input("请输入你要下载的张数[输入数字]:"))

第三步:逻辑分析

找到用户输入的参数生成必要参数,由于一次最多获得200张数据,所以需要判断是否超过200,并且超过200的值。例如:用户输入850张,由于每次200张下载,所以我们可以下载4次每次200张的,还要下载1次50张的才能下载完成。

# 定制参数规则
if input_count > 200:
    index = input_count // 200
    count = input_count % 200
else:
    index = 0
    count = input_count

举个例子帮你们理解一下:
用户A 选择 下载 “美女模特” 种类,850张 ,根据前面的图片分类可以知道 “美女模特” 的 cid 是6
再根据上面的定制参数规则可以算出:我们需要下载 4 次200张的 还要再下载一次50张的才能够下载完成。
我们现在一共获得3个参数:

  • 图片的种类 --6
  • 整数下载次数–4
  • 余数下载次数–50

所以我们定义两个函数:
第一个函数接收这三个参数,构造三种情况的 接口url:

"""
没有余数:
    没有余数可以直接整数下载
没有整数:
    没有整数直接余数下载
有整数,有余数:
    有整数,有余数,先整数下载,再余数下载
"""

第二个函数接收接口url,获得每张图片的 id 和 下载地址。

第四步:定义函数

函数实现:

def get_img_url(img_cid, for_index, img_count):  # 接受上面获得的三个数据
    """
    判断传入参数,构建图片接口
    :param img_cid: 图片种类
    :param for_index: 循环次数
    :param img_count: 剩余张数
    :return: 返回所有图片地址 字典{图片名:图片地址}
    """
	# 再函数中定义了一个函数,传入 接口url 进行访问,获得图片的 id 和 图片URL地址
    def requests(img_url):
        """
        根据传入的接口url进行访问
        :param img_url: 图片接口url
        :return: None
        """
        try:
            # 访问数据
            response = request.urlopen(url=img_url)
            # 转换到 json
            response = json.loads(response.read().decode("utf-8"))["data"]
            # 循环获得图片 id 和图片地址,图片 id 用于图片名字
            for resp in response:
                mid_url = resp["url_mid"]
                # 将图片 id 格式化成保存路径,我这里保存在项目目录下的 img 文件夹中(要自行创建)
                url_path = "./img/" + resp["id"] + ".jpg"
                return_list.append((url_path, mid_url))
        except Exception as e:
            print(f"{img_url} 发生访问错误:{e}")

    # 声明一个变量,用于存储 图片的 id 和 图片 url 地址 ---格式:[{图片名:url}]
    return_list = []
    # 逻辑判断,构建图片接口
    if img_count == 0:
        # 没有余数,200的倍数
        for i in range(for_index):
            url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start={i * 200 + 1}&count=200"
            requests(url)
    elif for_index == 0:
        # 没有整数,只有余数
        url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start=0&count={img_count}"
        requests(url)
    elif img_count > 0:
        # 有余数,先访问整数
        for i in range(for_index):
            url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start={i * 200 + 1}&count=200"
            requests(url)
        # 再访问余数
        url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start={for_index * 200 +1}&count={img_count}"
        requests(url)


    # 返回所有图片地址
    return return_list

这样我们就获得了用户输入的图片的所有张数信息,并将之存在列表中,以返回值的形式返回。

# 传入参数获得图片名称和地址
img_list = get_img_url(input_cid, index, count)

第五步:下载图片到本地

有了数据以后,我们就可以将图片下载到本地了
定义一个下载函数,接收 图片路径(根据图片id格式化获得,上述函数中有提到)和下载地址(url):

def download(file_path, url):
    """
    下载图片到本地
    :param file_path: 图片路径
    :param url: 图片地址
    :return: None
    """
    try:
        request.urlretrieve(url, file_path)
    except Exception as e:
        print(f"{file_path, url} 发生下载错误:{e}")

通过循环获得的图片列表,提取图片的路径和url 进行下载,两种下载方式:

  • 第一种,直接循环调用函数进行下载
# 传入参数获得图片名称和地址
img_list = get_img_url(input_cid, index, count)

for img in img_list:
    download(img[0], img[1])
# 速度可能有点慢,尤其是大量下载的时候
  • 第二种,使用 threading 模块 进行下载
# 传入参数获得图片名称和地址
img_list = get_img_url(input_cid, index, count)

# 声明线程列表
thread_list = []
# 构造线程
for img in img_list:
    thread_list.append(threading.Thread(target=download, args=(img[0], img[1])))
# 循环启动线程
for t in thread_list:
    t.start()
# 相对来说会快一点

这样,我们就完成了壁纸的下载。

完整代码

# code = "utf-8"

from urllib import request
import json
import threading

"""

接口url: https://zvvx.cn/one/bizhi/api.php?cid=36&start=0&count=30

提取接口规则
cid=6 分类
start=0 开始位置
count=30 获取张数 实测最多200张有数据,超过200张没有数据
"""


def get_img_url(img_cid, for_index, img_count):
    """
    判断传入参数,构建图片接口
    :param img_cid: 图片种类
    :param for_index: 循环次数
    :param img_count: 剩余张数
    :return: 返回所有图片地址 字典{图片名:图片地址}
    """
    def requests(img_url):
        """
        获取图片名称和下载地址
        :param img_url: 图片接口地址
        :return: None
        """
        try:
            # 访问数据
            response = request.urlopen(url=img_url)
            # 转换到 json
            response = json.loads(response.read().decode("utf-8"))["data"]
            # 循环获得图片 id 和图片地址,图片 id 用于图片名字
            for resp in response:
                mid_url = resp["url_mid"]
                url_path = "./img/" + resp["id"] + ".jpg"
                return_list.append((url_path, mid_url))
        except Exception as e:
            print(f"{img_url} 发生访问错误:{e}")

    # 声明返回值
    return_list = []
    # 逻辑判断,构建图片接口
    if img_count == 0:
        # 没有余数,200的倍数
        for i in range(for_index):
            url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start={i * 200 + 1}&count=200"
            requests(url)
    elif for_index == 0:
        # 没有整数,只有余数
        url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start=0&count={img_count}"
        requests(url)
    elif img_count > 0:
        # 有余数,先访问整数
        for i in range(for_index):
            url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start={i * 200 + 1}&count=200"
            requests(url)
        # 再访问余数
        url = f"https://zvvx.cn/one/bizhi/api.php?cid={img_cid}&start={for_index * 200 +1}&count={img_count}"
        requests(url)

    # 返回所有图片地址
    return return_list


def download(file_path, url):
    """
    下载图片到本地
    :param file_path: 图片路径
    :param url: 图片地址
    :return: None
    """
    try:
        request.urlretrieve(url, file_path)
    except Exception as e:
        print(f"{file_path, url} 发生下载错误:{e}")


if __name__ == '__main__':

    # 分类列表
    class_dict = {
        "4K专区": 36,
        "美女模特": 6,
        "爱情美图": 30,
        "风景大片": 9,
        "小清新": 15,
        "动漫卡通": 26,
        "明星风尚": 11,
        "萌宠动物": 14,
        "游戏壁纸": 5,
        "汽车天下": 12,
        "炫酷时尚": 10,
        "月历壁纸": 29,
        "影视剧照": 7,
        "节日美图": 13,
        "军事天地": 22,
        "劲爆体育": 16,
        "BABY秀": 18,
        "文字控": 35
    }

    # 向屏幕输出图片分类信息
    print("以下分类请选择:")
    for c in class_dict:
        print(c, class_dict[c])

    # 用户输入参数以下载
    input_cid = int(input("请输入你要下载的分类[输入数字]:"))
    input_count = int(input("请输入你要下载的张数[输入数字]:"))
    # 定制参数规则
    if input_count > 200:
        index = input_count // 200
        count = input_count % 200
    else:
        index = 0
        count = input_count
    # 传入参数获得图片名称和地址
    img_list = get_img_url(input_cid, index, count)
    # 声明线程列表
    thread_list = []
    # 构造线程
    for img in img_list:
        thread_list.append(threading.Thread(target=download, args=(img[0], img[1])))
    # 循环启动线程
    for t in thread_list:
        t.start()

结果展示:

运行结果
下载结果
该文章仅供学习和交流。

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巷子里的猫灬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值