【kimol君的无聊小发明】—用python写图片下载器

  • 前言
  • 一、单线程版
  • 二、多线程版
  • 写在最后

Tip:本文仅供学习与参考,且勿用作不法用途~

前言

某个夜深人静的夜晚,我打开了自己的文件夹,发现了自己写了许多似乎很无聊的代码。于是乎,一个想法油然而生:“生活已经很无聊了,不如再无聊一点叭”。
说干就干,那就开一个专题,我们称之为kimol君的无聊小发明。
妙…啊~~~

网上爬虫入门教程有很多,大多是从下载图片开始~正经人谁不下载一下图片呢,对叭?
kimol君也不例外,咱上图瞧一瞧:

一、单线程版

关于该网站的爬取应该来说是比较入门的了,因为并没涉及到太多的反爬机制,据目前来看主要有两点:

  • headers中Referer参数:其解决方法也很简单,只需要在请求头中加入这个参数就可以了,而且也不需要动态变化,固定为主页地址即可。
  • 请求速度限制:在实际爬取过程中我们会发现,如果爬取速度过快IP往往会被封了,而这里我们只需要适当限制速度或者加入代理池即可。

具体的爬虫分析,网上随便一搜就是一堆,我这里就直接献上代码好了:

# =============================================================================
# Mzitu图片爬取
# =============================================================================
import re
import os
import time
import queue
import requests
from tqdm import tqdm
from termcolor import *
from colorama import init# 解决CMD无法显示颜色问题
init(autoreset=False)class spider_Mzidu():def __init__(self):# 定义请求地址self.url_page = 'https://www.mzitu.com/page/%d/' # 搜索页面(用以获取ID)self.url_taotu = 'https://www.mzitu.com/%s'      # 页面(用以获取图片地址)# 定义请求头self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0','Accept': '*/*','Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2','Accept-Encoding': 'gzip, deflate, br','X-Requested-With': 'XMLHttpRequest','Connection': 'keep-alive','Referer': 'https://www.mzitu.com',}# 定义正则表达式self.p_id = '<span><a href="https://www.mzitu.com/(\d*?)" target="_blank">(.*?)</a></span>'self.p_imgurl = '<img class="blur" src="(.*?)"'self.p_page = '…</span>.*?<span>(\d*?)</span>'# 存储变量self.queue_id = queue.Queue()def getPages(self): # 获取总页数res = requests.get(self.url_page%1,headers=self.headers)html = res.textN = re.findall('''class="page-numbers dots">[\s\S]*?>(\d*?)</a>[\s\S]*?"next page-numbers"''',html)[0]return int(N)def getID(self): # 获取IDpage_range = input('请输入爬取页数(如1-10):')p_s = int(page_range.split('-')[0])p_e = int(page_range.split('-')[1])time.sleep(0.5)print(colored('开始获取套图ID'.center(50,'-'),'green'))bar = tqdm(range(p_s,p_e+1),ncols=60) # 进度条for p in bar:res = requests.get(self.url_page%p,headers=self.headers)html = res.textids = re.findall(self.p_id,html)for i in ids:self.queue_id.put(i)bar.set_description('第%d页'%p)def downloadImg(self,imgurl): # 下载图片res = requests.get(imgurl,headers=self.headers)img = res.contentreturn imgdef parseTaotu(self,taotuID): # 解析"图片数量",以及"图片地址"res = requests.get(self.url_taotu%taotuID,headers=self.headers)html = res.textpage = int(re.findall(self.p_page,html)[0])imgurl = re.findall(self.p_imgurl,html)[0]imgurl = imgurl[:-6]+'%s'+imgurl[-4:]return(imgurl,page)def downloadTaotu(self): # 下载 while not self.queue_id.empty():taotu = self.queue_id.get()taotuID = taotu[0]taotuName = taotu[1]try:imgurl,page = self.parseTaotu(taotuID)path = '[P%d]'%page+taotuNameif not os.path.exists(path):os.mkdir(path)bar = tqdm(range(1,page+1),ncols=50) # 进度条for i in bar:url = imgurl%(str(i).zfill(2))img = self.downloadImg(url)with open('./%s/%d.jpg'%(path,i),'wb') as f:f.write(img)print('套图("'+colored(taotuName,'red')+'")爬取完成')except:time.sleep(3)self.queue_id.put(taotu)def run(self): # 主程序os.system('cls')  # 清空控制台print('*'*35)print('*'+'欢迎使用Mzitu下载器'.center(26)+'*')print('*'*35)N = self.getPages()print(('Mzitu当前共有%s页!'%colored(N,'red')).center(30))print('\n')self.getID()print('\n'+colored('开始爬取套图'.center(50,'-'),'green'))self.downloadTaotu()spider = spider_Mzidu()
spider.run()

二、多线程版

有小伙伴估计得问了:“单线程这么慢?您是在开玩笑的叭,等得我不得憋坏咯?”
客官这边请,来试试多线程版的好了:

# =============================================================================
# Mzitu图片爬取(多线程)
# =============================================================================
import re
import os
import time
import queue
import requests
import threading
from tqdm import tqdm
from termcolor import *
from colorama import init# 解决CMD无法显示颜色问题
init(autoreset=False)# 代理(XXX代理)
def Get_proxy():res = requests.get('xxxxxxxxxxxxxxxxxxx')html = res.textreturn htmlclass spider_Mzidu():def __init__(self):# 定义请求地址self.url_page = 'https://www.mzitu.com/page/%d/' # 搜索页面(用以获取ID)self.url_taotu = 'https://www.mzitu.com/%s'      # 页面(用以获取地址)# 定义请求头self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0','Accept': '*/*','Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2','Accept-Encoding': 'gzip, deflate, br','X-Requested-With': 'XMLHttpRequest','Connection': 'keep-alive','Referer': 'https://www.mzitu.com',}# 定义正则表达式self.p_id = '<span><a href="https://www.mzitu.com/(\d*?)" target="_blank">(.*?)</a></span>'self.p_imgurl = '<img class="blur" src="(.*?)"'self.p_page = '…</span>.*?<span>(\d*?)</span>'# 存储变量self.queue_id = queue.Queue()#HTTP代理proxy = Get_proxy()self.proxies = {'http':'http://'+proxy,'https':'https://'+proxy} def getPages(self): # 获取总页数res = requests.get(self.url_page%1,headers=self.headers,proxies=self.proxies,timeout=10)html = res.textN = re.findall('''class="page-numbers dots">[\s\S]*?>(\d*?)</a>[\s\S]*?"next page-numbers"''',html)[0]return int(N)def getID(self): # 获取IDpage_range = input('请输入爬取页数(如1-10):')p_s = int(page_range.split('-')[0])p_e = int(page_range.split('-')[1])time.sleep(0.5)print(colored('开始获取套图ID'.center(50,'-'),'green'))bar = tqdm(range(p_s,p_e+1),ncols=60) # 进度条for p in bar:res = requests.get(self.url_page%p,headers=self.headers,proxies=self.proxies,timeout=10)html = res.textids = re.findall(self.p_id,html)for i in ids:self.queue_id.put(i)bar.set_description('第%d页'%p)def downloadImg(self,imgurl,proxies): # 下载图片res = requests.get(imgurl,headers=self.headers,proxies=proxies,timeout=10)img = res.contentreturn imgdef parseTaotu(self,taotuID,proxies): # 解析的"图片数量",以及"图片地址"res = requests.get(self.url_taotu%taotuID,headers=self.headers,proxies=proxies,timeout=10)html = res.textpage = int(re.findall(self.p_page,html)[0])imgurl = re.findall(self.p_imgurl,html)[0]imgurl = imgurl[:-6]+'%s'+imgurl[-4:]return(imgurl,page)def downloadTaotu(self): # 下载 proxy = Get_proxy()proxies = {'http':'http://'+proxy,'https':'https://'+proxy} while not self.queue_id.empty():taotu = self.queue_id.get()taotuID = taotu[0]taotuName = taotu[1]try:imgurl,page = self.parseTaotu(taotuID,proxies)path = '[P%d]'%page+taotuNameif not os.path.exists(path):os.mkdir(path)bar = tqdm(range(1,page+1),ncols=50) # 进度条for i in bar:url = imgurl%(str(i).zfill(2))img = self.downloadImg(url,proxies)with open('./%s/%d.jpg'%(path,i),'wb') as f:f.write(img)print('套图("'+colored(taotuName,'red')+'")爬取完成')except:time.sleep(3)proxy = Get_proxy()proxies = {'http':'http://'+proxy,'https':'https://'+proxy} self.queue_id.put(taotu)def changeProxy(self): # 更换代理proxy = Get_proxy()self.proxies = {'http':'http://'+proxy,'https':'https://'+proxy} def run(self): # 主程序os.system('cls')  # 清空控制台print('*'*35)print('*'+'欢迎使用Mzitu下载器'.center(26)+'*')print('*'*35)N = self.getPages()print(('Mzitu当前共有%s页!'%colored(N,'red')).center(30))print('\n')self.getID()print('\n'+colored('开始爬取套图'.center(50,'-'),'green'))# 多线程下载N_thread = 3thread_list = []for i in range(N_thread):thread_list.append(threading.Thread(target=self.downloadTaotu))for t in thread_list:t.start()for t in thread_list:t.join()spider = spider_Mzidu()
spider.run()

细心的大大应该发现了,其实多线程版跟单线程版结构上几乎没有太大的差别(这里也提供了一种代码思路,这样使得如果我们以后想把原来代码改为多线程,可以更加方便快捷),主要是这两点:

  • 调用downloadTaotu()函数的时候,使用threading模块开启多线程多次调用。
  • 加入了HTTP代理模块。这里大家可以酌情考虑是否保留,不过根据我测试发现,如果是使用多线程的话,建议大家还是加入代理,不然IP很可能被封。

写在最后

如果大家对代码里的进度条或者输出的文字颜色感兴趣,让自己的代码输出更风骚,大家可以参考这里。(Python炫酷的颜色输出与进度条打印)

文中如有不足,还望大家批评指正!
最后,感谢各位大大的耐心阅读~
慢着,大侠请留步… 动起可爱的双手,来个赞再走呗 (๑◕ܫ←๑)

【kimol君的无聊小发明】—用python写图片下载器相关推荐

  1. python小工具小发明_【kimol君的无聊小发明】—用python写截屏小工具

    前言 今天我看了一下自己的文件夹,发现了自己写了许多似乎很无聊的代码.于是乎,一个想法油然而生:"生活已经很无聊了,不如再无聊一点叭". 说干就干,那就开一个专题,我们称之为kim ...

  2. 【kimol君的无聊小发明】—用python插入独创性声明

    [kimol君的无聊小发明]-用python插入独创性声明 前言 一.代码分析 二.完整代码 写在最后 前言 某个夜深人静的夜晚,夜微凉风微扬,月光照进我的书房~ 当我打开文件夹以回顾往事之余,惊现许 ...

  3. 【kimol君的无聊小发明】—用python写论文下载器

    [kimol君的无聊小发明]-用python写论文下载器 前言 一.代码分析 1. 搜索论文 2. 下载论文 二.完整代码 写在最后 前言 某个夜深人静的夜晚,夜微凉风微扬,月光照进我的书房~ 当我打 ...

  4. 【kimol君的无聊小发明】—用python写PDF转换器

    [kimol君的无聊小发明]-用python写PDF转换器 前言 一.思路分析 二.我的代码 写在最后 前言 某个夜深人静的夜晚,夜微凉风微扬,月光照进我的书房~ 当我打开文件夹以回顾往事之余,惊现许 ...

  5. 【kimol君的无聊小发明】—用python写截屏小工具

    [kimol君的无聊小发明]-用python写截屏小工具 前言 一.技术实现 1. 相关库 2. 定义窗口 3. 绘制工具条 4. 定义事件函数 二.后续改进 写在最后 前言 今天我看了一下自己的文件 ...

  6. 【kimol君的无聊小发明】—用python写图片格式批量处理工具

    [kimol君的无聊小发明]-用python写图片格式批量处理工具 前言 一.思路分析 二.调整尺寸 三.调整大小 四.整合代码 写在最后 前言 某个夜深人静的夜晚,夜微凉风微扬,月光照进我的书房~ ...

  7. 【kimol君的无聊小发明】—用python写论文下载器(图形化界面)

    [kimol君的无聊小发明]-用python写论文下载器(图形化界面) 前言 一.使用说明 二.代码分析 1. 功能函数 2. 回调函数 3. 线程生成函数 4. 效果展示 写在最后 前言 某个夜深人 ...

  8. 可以用python实现一些小发明_【kimol君的无聊小发明】—用python写图片格式批量处理工具...

    前言某个夜深人静的夜晚,夜微凉风微扬,月光照进我的书房~ 当我打开文件夹以回顾往事之余,惊现许多看似杂乱的无聊代码.我拍腿正坐,一个想法油然而生:"生活已然很无聊,不如再无聊些叭" ...

  9. 【kimol君的无聊小发明】—用python写视频下载器

    [kimol君的无聊小发明]-用python写视频下载器 前言 一.爬虫分析 1.视频搜索 2.视频下载 二.我的代码 写在最后 Tip:本文仅供学习与参考,且勿用作不法用途~ 前言 某个夜深人静的夜 ...

最新文章

  1. CVPR 2021 | 视觉目标检测大模型GAIA:面向行业的视觉物体检测一站式解决方案
  2. 【Android 逆向】ELF 文件格式 ( ELF 文件类型 | ELF 文件对应 CPU 架构 | ELF 目标文件版本 | 可执行程序起始地址 )
  3. Android --- Serializable 接口与 Parcelable 接口的使用方法和区别,怎么选择?
  4. Java9中的GC 调优
  5. django08: 视图与路由(旧笔记)
  6. linux扩容根目录空间_Linux系统扩容根目录磁盘空间的操作方法
  7. MySQL分页查询小技巧
  8. Oracle内存管理(五)
  9. oracle数据库的字符集更改
  10. 《网络工程师考试 考前冲刺预测卷及考点解析》复习重点
  11. DefaultKeyedVector和KeyedVector用法
  12. JavaScript中对象的属性:如何遍历属性
  13. CSDN下载码怎么使用
  14. 课题申报书范文_课题优秀申报书 课题申报书范例
  15. 动态IP和静态IP区别,别傻傻分不清楚!
  16. 关于JavaScript(JS)
  17. 在centos上安装vmware14
  18. 用自己的路由器建立自己的服务器之创建网页
  19. 台大·林轩田·机器学习基石·第二讲
  20. 重拾Java基础知识:IO流

热门文章

  1. 手把手教你修改Firefox的User-Agent伪装Android微信浏览器
  2. android模拟器 出错:X Error of failed request: BadRequest (invalid request code or no such operation)
  3. ただの南條きみつだ。
  4. 北邮复试 | 北邮机试往年题汇总 | 计算机院 | 网研院 | 网安院 | 软院
  5. 以核心技术提升打破认知偏见:破解第三代哈弗H6的技术密码
  6. 计算机 实验室安全准入制度,华东理工大学实验室安全准入制度
  7. html鼠标拖尾效果,前端每日实战:25# 视频演示如何用纯 CSS 创作一个慧星拖尾效果的 loader 动画...
  8. java 指定垃g1圾收集_java垃圾回收G1收集器
  9. 金山词霸致 Internet Explorer 延迟打开问题
  10. Qt+百度API实现人脸对比寻找明星脸