python爬虫实战——自动下载百度图片(文末附源码)
用Python制作一个下载图片神器
前言
这个想法是怎么来的?
很简单,就是不想一张一张的下载图片,嫌太慢。
在很久很久以前,我比较喜欢收集各种动漫的壁纸,作为一个漫迷,自然是能收集多少就收集多少。小孩子才做选择,我全都要。但是用鼠标一个个点击下载,这也太low啦!于是最终放弃啦。
现在,这个想法在我脑中不停地出现,如果不解决它,我会茶不思饭不想,难受至极!
于是,我竭尽全力的挤出时间(上班摸鱼的时候),终于完成了这一”举世瞩目“的工程。现在仅需输入需要下载的图片内容、图片数量,就可以快速的拥有数不尽的”荣华富贵“。
接下来,看一看这是如何实现的(让一让,我要开始装B啦),授人鱼不如授人以渔。
分析百度图片网站
为什么是百度图片,而不是其他网站?
我不想回答,咱直接开始分析,好吧。
怎么检查网站的构造?
以谷歌浏览器为例,右击选择“检查”,就可以看到网站的源码,以及整个结构。
那百度图片网站是如何工作的,或者如何加载图片的?
当我在搜索框中输入《秦时明月》后,点击百度一下,图片并不会全部展示完,而是先加载一部分数据,当页面滑动到最后一张图片后,页面会继续加载图片。这种加载数据的方式,被称为“异步加载”。
对于这种异步加载得到的数据,选择“Network”选项卡,在选中“XHR”,这里面加载的内容就是异步加载的内容。如下图:

点击左侧的接口地址,在右侧选择“Preview”选项,就可以看到该接口返回的json数据。在这个接口中发现:fromPageTitleEnc为图片的标题,hoverURL为图片的真正地址。如下图:
 
知道图片的加载方式,然后呢?
现在接口的地址如下:
url = "https://image.baidu.com/search/acjson"
接下来就是要”伪造“请求头(header)以及请求参数(param),模拟浏览器去访问接口。
刚开始可以将浏览器中所有的数据复制下来,去请求接口,经过我的一番测试,发现请求头只需要以下参数即可:
header = {
    'Accept': 'text/plain, */*; q=0.01',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Host': 'image.baidu.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
}
请求参数如下:
其中,重要的参数为:
- queryWord:word,查询词
- rn:代表接口返回的图片数量为30张
- pn:以30为基础,60表示第二个接口,90表示第三个接口,120表示第四个接口
其他参数,我也不知道有啥用!放着不要动就行。
param = {
    'tn': 'resultjson_com',
    'ipn': 'rj',
    'ct': '201326592',
    'fp': 'result',
    'queryWord': '秦时明月',
    'cl': '2',
    'lm': '-1',
    'ie': 'utf-8',
    'oe': 'utf-8',
    'st': '-1',
    'ic': '0',
    'word': '秦时明月',
    'face': '0',
    'istype': '2',
    'nc': '1',
    'pn': '60',
    'rn': '30',
    'gsm': '1e',
}
所以,只需修改queryWord,word,pn即可获取不同类型图片,不同数量的图片。
爬虫
能否谈一下你的爬虫代码思路?
talk is cheap,show me the code!(话不多说,都在代码里!)
1、获取json数据
def get_json(query_word=None, page_num=None):
    # 修改参数中的查询关键词
    param["queryWord"] = query_word
    param["word"] = query_word
    # 修改获取图片的数量
    param["pn"] = f'{30 * page_num}'
    # 模拟浏览器获取json数据
    res = requests.get(url=url, headers=header, params=param)
    res_dict = dict(res.json())
    return res_dict
2、解析数据
def get_pic_info(res=None):
    # 将图片信息都放到 pic_info 列表中
    pic_info = []
    for data in res["data"]:
        # 从 json 数据中解析出数据
        pic_name = data.get("fromPageTitleEnc", None)
        pic_url = data.get("hoverURL", None)
        # 以 pic_name 为名命名图片
        if pic_name and pic_url:
            pic_name = pic_name.replace(" ", '')
            for p in string.punctuation:
                pic_name = pic_name.replace(p, '')
            if "png" in pic_url:
                pic_name += ".png"
            if "jpg" in pic_url:
                pic_name += ".jpg"
            if "gif" in pic_url:
                pic_name += ".gif"
            if "jpeg" in pic_url:
                pic_name += ".jpeg"
            if "bmp" in pic_url:
                pic_name += ".bmp"
            pic_info.append({"pic_name": pic_name, "pic_url": pic_url})
    return pic_info
3、保存图片
def save_picture(query_word=None, pic_name=None, pic_url=None):
    # 在同级目录下创建 image 文件夹,将图片保存在以 query_word 为名创建新的文件夹
    cwd = os.getcwd()
    images_path = os.path.join(cwd, "images")
    query_word_path = os.path.join(images_path, query_word)
    # images 文件夹
    if "images" not in os.listdir(cwd):
        os.mkdir(images_path)
    # os.chdir(images_path)
    # query_word 文件夹
    if query_word not in os.listdir(images_path):
        os.mkdir(query_word_path)
    # 读取图片
    pic = requests.get(pic_url, stream=True)
    pic_path = os.path.join(query_word_path, pic_name)
    # 保存图片
    with open(pic_path, "wb") as f:
        for c in pic.iter_content(chunk_size=10240):
            f.write(c)
4、主运行代码
def run():
    while True:
        # 多次下载,直到输入 q 退出
        query_word = str(input("输入要下载的图片名(q退出):"))
        if query_word == "q":
            break
        while True:
            # 当输入的数量不为整数,循环输入
            pic_num = input("输入需要下载的数量(q退出):")
            if pic_num == "q":
                break
            try:
                pic_num = int(pic_num)
            except:
                continue
            page_num = 1 if int(pic_num / 30) == 0 else int(pic_num / 30)
            for i in range(1, page_num + 1):
                # 获取 json 数据
                res = get_json(query_word=query_word, page_num=i)
                # 获取图片名和图片地址
                pic_info = get_pic_info(res=res)
                # 保存图片
                for pic in pic_info:
                    print(pic["pic_name"], "下载完成")
                    save_picture(query_word=query_word, pic_name=pic["pic_name"], pic_url=pic["pic_url"])
            break
if __name__ == '__main__':
    run()
这么多代码,没有基础的我,不想看,咋办?
不要方,少年,接下来有更加神奇的操作,如何将这些代码封装为exe文件,这样就算你没有python环境,也可以使用。
生成exe文件
请问,将python文件打包成exe文件总共分几步?
第一步:将用到的第三方库requests与该py文件同级目录下,如下图:

第二步:安装pyinstaller
pip installer pyinstaller
第三步:打包
pyinstaller -F py文件的绝对地址
更改图标,图标只能是ico文件
pyinstaller -i -F ico图片地址 py文件的绝对地址
好了,这里就介绍这么多,感兴趣的同学给个关注呗!
更多好玩的内容,欢迎关注微信公众号“数据与编程之美”

python爬虫实战——自动下载百度图片(文末附源码)的更多相关文章
- C# 30分钟完成百度人脸识别——进阶篇(文末附源码)
		距离上次入门篇时隔两个月才出这进阶篇,小编惭愧,对不住关注我的卡哇伊的小伙伴们,为此小编用这篇博来谢罪. 前面的准备工作我就不说了,注册百度账号api,创建web网站项目,引入动态链接库引入. 不了解 ... 
- python爬虫-淘宝商品密码(图文教程附源码)
		今天闲着没事,不想像书上介绍的那样,我相信所有的数据都是有规律可以寻找的,然后去分析了一下淘宝的商品数据的规律和加密方式,用了最简单的知识去解析了需要的数据. 这个也让我学到了,解决问题的方法不止一个 ... 
- 基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
		今天我们来盘一盘Socket通讯和WebSocket协议在即时通讯的小应用——聊天. 理论大家估计都知道得差不多了,小编也通过查阅各种资料对理论知识进行了充电,发现好多demo似懂非懂,拷贝回来又运行 ... 
- C# Queue与RabbitMQ的爱恨情仇(文末附源码):Q与MQ消息队列简单应用(二)
		上一章我们讲了队列( Queue),这一章我们讲Message Queue消息队列,简称MQ. 定义: MQ是MessageQueue,消息队列的简称(是流行的开源消息队列系统,利用erlang语言开 ... 
- 手把手教你基于SqlSugar4编写一个可视化代码生成器(生成实体,以SqlServer为例,文末附源码)
		在开发过程中免不了创建实体类,字段少的表可以手动编写,但是字段多还用手动创建的话不免有些浪费时间,假如一张表有100多个字段,手写有些不现实. 这时我们会借助一些工具,如:动软代码生成器.各种ORM框 ... 
- python根据搜索词下载百度图片
		# coding=utf-8 """根据搜索词下载百度图片""" import re import urllib import os def ... 
- Python爬虫实战 批量下载高清美女图片
		彼岸图网站里有大量的高清图片素材和壁纸,并且可以免费下载,读者也可以根据自己需要爬取其他类型图片,方法是类似的,本文通过python爬虫批量下载网站里的高清美女图片,熟悉python写爬虫的基本方法: ... 
- python爬虫实战(3)--图片下载器
		本篇目标 1.输入关键字能够根据关键字爬取百度图片 2.能够将图片保存到本地文件夹 1.URL的格式 进入百度图片搜索apple,这时显示的是瀑布流版本,我们选择传统翻页版本进行爬取.可以看到网址为: ... 
- python爬虫之爬取百度图片
		##author:wuhao##爬取指定页码的图片,如果需要爬取某一类的所有图片,整体框架不变,但需要另作分析#import urllib.requestimport urllib.parseimpo ... 
- 用python的TK模块实现猜成语游戏(附源码)
		说明:本游戏使用到的python模块有tkinter,random,hashlib:整个游戏分为四个窗口,一个进入游戏的窗口.一个选关窗口.一个游戏进行窗口和一个游戏结束的窗口. 源码有两个主要的py ... 
随机推荐
- JavaScript 对象操作
			Object.defineProperty(obj, prop, descriptor)方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象. const freezeO ... 
- CCF 201912-2	回收站选址
			#include <iostream> #include <bits/stdc++.h> #include <string> using namespace std ... 
- Java基础学习:7、作用域
			1.在Java中,主要的变量就是属性(成员变量)和局部变量. 2.我们说的局部变量一般是指在成员方法中定义的变量. 3.Java作用域分类: 全局变量:作用域为整个类,该类中的方法可以使用. 局部变量 ... 
- FCOS网络(free anchor)
			FCOS FCOS网络解析 FPN输出多个特征图,然后如何处理这些特征图? [问题]"特征图相对原图的步距是s"是个什么东西 
- Quartz 2D CGPattern学习笔记
			CGPattern是在图形上下文中重复绘制的一系列绘制操作.你可以像使用颜色一样使用图案.当使用CGPattern进行绘制时,Quartz将页面划分为一组图案单元格,每个单元格的大小为CGPatter ... 
- iptables( < deb ufw)
			iptables其实不是真正的防火墙,可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的netfilter安全框架"中,netfilter位于内核空 ... 
- 成品直播源码,Flutter 夜间模式 全局字体
			成品直播源码,Flutter 夜间模式 全局字体 import 'package:flutter/material.dart';import 'package:flutter_widget/route ... 
- MyBatis_07(动态SQL)
			动态SQL: Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能, 它存在的意义是:"为了解决拼接SQL语句字符串时的痛点问题". 一.If if标签可通 ... 
- git(后悔药)版本回退
			版本回退 查看提交记录 git log remotes/origin/test --pretty=oneline (建议获取远程日志记录,防止本地没有更新到最新版本) 如果本地是最新版本可以使用:gi ... 
- jabc连接数据库
			Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法.JD ... 
