斗图狂魔必备沙雕表情包,python多线程爬取斗图啦表情图片
混迹网络,表情包必不可少,从表情包图片的出现,无疑是席卷网络聊天的态势,涌现了不少网络神图,同时也培养了不少斗图狂魔,今天的沙雕图片你收藏了么?
作为py大(渣)婶(渣),沙雕图片怎么能够缺少呢?网络上有不少表情包图片网站,so,python走起来,搞起!
目标网站:http://www.doutula.com/ 斗图啦
爬取效果:
多线程爬取效果:
几个关键点:
1.图片名规范
由于我们下载图片是以网页上的alt属性命名,在存储为文件名的时候,需要对文本进行规范,某些特殊字符是不能作为图片名存储的!
使用 re.sub函数 把不符合规范的字符 替换
import re
imgname=re.sub(r'[|/<>:*?\"]','_',imgname)
2.图片名后缀的获取
图片名后缀,比如gif,jpg,这里可以导入os库的 os.path.splitext 直接切分网页图片地址!
import os
suffix = os.path.splitext(img_url)[1] #获取后缀名
3.关于图片的下载,request.urlretrieve函数
注意,需要添加协议头!
from urllib import request
opener =request.build_opener()
opener.addheaders = [('User-Agent',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
request.install_opener(opener)
request.urlretrieve(img_url, '%s%s'%('doutula/',img_name))
使用request.urlretrieve函数还存在这样一个问题,那就是网络延迟,会容易卡死,这里搜索了一个解决方法,案例参考!
如果有更好的方法不妨留言交流!
#下载文件出现urllib.ContentTooShortError且重新下载文件会存在用时过长的问题,而且往往会尝试好几次,甚至十几次,偶尔会陷入死循环,这种情况是非常不理想的。
#为此,笔者利用socket模块,使得每次重新下载的时间变短,且避免陷入死循环,从而提高运行效率。
import socket
import urllib.request
#设置超时时间为30s
socket.setdefaulttimeout(30)
#解决下载不完全问题且避免陷入死循环
try:
urllib.request.urlretrieve(url,image_name)
except socket.timeout:
count = 1
while count <= 5:
try:
urllib.request.urlretrieve(url,image_name)
break
except socket.timeout:
err_info = 'Reloading for %d time'%count if count == 1 else 'Reloading for %d times'%count
print(err_info)
count += 1
if count > 5:
print("downloading picture fialed!")
#来源:CSDN博主「山阴少年」
4.关于图片路径的获取
使用etree解析网页的方式,注意图片路径的获取,这里使用了img[@class!="gif"]排除了多余图片的干扰!
imgs=html.xpath('//div[@class="page-content text-center"]/div//a/img[@class!="gif"]')
5.queue库的使用
queue队列的使用,控制数据的进出,避免多线程错乱!
加入队列:queue.put()
取出队列:queue.get()
获取队列消息个数:queue.qsize()
提示:如果队列满了,那么使用put放入数据会等待,直到队列有空闲位置才可以放入 放入消息的时候不会进行等待,如果发现队列满了不能放入数据,那么会直接崩溃
import multiprocessing
import time
if __name__ == '__main__':
# 创建消息队列
# 3:表示消息队列的最大个数
queue = multiprocessing.Queue(3)
# 存放数据
queue.put(1)
queue.put("hello")
queue.put([1, 5, 8])
# 总结: 队列可以放入任意类型的数据
# 提示: 如果队列满了,那么使用put放入数据会等待,直到队列有空闲位置才可以放入
# queue.put(("xxx", "yyy"))
# 放入消息的时候不会进行等待,如果发现队列满了不能放入数据,那么会直接崩溃
# 建议: 放入数据统一put方法
# queue.put_nowait(("xxx", "yyy"))
# 判断队列是否满了
result = queue.full()
print("队列是否满了:", result)
# 使用empty判断队列是否为空,不靠谱
# 解决办法:
time.sleep(0.01)
# 解决办法: 可以通过qsize判断,但是mac版本没有qsize
result = queue.empty()
print("队列是否为空:", result)
# 获取队列消息的个数
size = queue.qsize()
print("消息个数:", size)
# 获取队列中数据
result = queue.get()
print(result)
# 获取队列消息的个数
size = queue.qsize()
print("消息个数:", size)
# 获取队列中数据
result = queue.get()
print(result)
# 获取队列消息的个数
size = queue.qsize()
print("消息个数:", size)
# 获取队列中数据
result = queue.get()
print(result)
# 获取队列消息的个数
size = queue.qsize()
print("消息个数:", size)
# 如果队列空了,那么使用get方法会等待队列有消息以后再取值
# result = queue.get()
# print(result)
# 取值的时候不等待,那么如果发现队列为空,取值不成功那么会直接崩溃
# 建议: 获取数据使用统一get方法
# result = queue.get_nowait()
# print(result)
#来源:CSDN博主「巨基呀。」
6.最关键的一点,也就是多线程的使用,python多线程生存者消费模型
import threading,time
import Queue
import random
q=Queue.Queue()
def Chan(name):
for i in range(5):
q.put(i)
print '%s shengchan %s baozi' %(name,i)
time.sleep(random.randrange(5))
def Chi(name):
count=0
while count < 5:
d=q.get()
print '%s chichichi %s baozi' %(name,d)
count +=1
time.sleep(random.randrange(5))
p=threading.Thread(target=Chan,args=('AAAAAAAAAAA',))
c=threading.Thread(target=Chi,args=('BBBBBBBBBBB',))
p.start()
#来源:CSDN博主「dyeee」
附上单线程代码:
#doutula.com采集
#20191217 by 微信 huguo002
import requests
from lxml import etree
from urllib import request
import os
from fake_useragent import UserAgent
import re
import time
def ua():
ua=UserAgent()
headers={'User-Agent':ua.random}
return headers
def parse(url):
opener =request.build_opener()
opener.addheaders = [('User-Agent',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
request.install_opener(opener)
response=requests.get(url,headers=ua(),timeout=10).content.decode('utf-8')
time.sleep(1)
html=etree.HTML(response)
imgs=html.xpath('//div[@class="page-content text-center"]/div//a/img[@class!="gif"]')
"""imgs = html.xpath('//div[@class="page-content text-center"]/div//a/img/@data-original')
print(imgs)
imgnames=html.xpath('//div[@class="page-content text-center"]/div//a/img/@alt')
print(imgnames)
for img_url,imgname in zip(imgs,imgnames):
print(img_url,'%s%s'%(imgname,os.path.splitext(img_url)[1]))
r=requests.get(img_url,headers=ua())
with open('doutula/'+'%s%s'%(imgname,os.path.splitext(img_url)[1]),'wb') as f:
f.write(r.content)
print("图片下载完成!")"""
for img in imgs:
img_url=img.get('data-original')
imgname=img.get('alt')
imgname=re.sub(r'[|/<>:*?\"]','_',imgname)
suffix = os.path.splitext(img_url)[1] #获取后缀名
img_name='%s%s'%(imgname,suffix)
print(img_url)
print(img_name)
try:
request.urlretrieve(img_url, '%s%s'%('doutula/',img_name))
print("图片下载完成!")
except:
pass
def main():
for i in range(1,101):
url="http://www.doutula.com/photo/list/?page=%d"% i
print(url)
parse(url)
if __name__=='__main__':
main()
附上多线程源码:
#doutula.com采集
#20191217 by 微信 huguo00289
import requests
from lxml import etree
from urllib import request
import os
from fake_useragent import UserAgent
import re
import time
import threading
from queue import Queue
#生产者
class Procuder(threading.Thread):
def __init__(self,page_queue,img_queue,*args,**kwargs):
super(Procuder,self).__init__(*args,**kwargs)
self.page_queue=page_queue
self.img_queue=img_queue
def run(self):
while True:
if self.page_queue.empty():
break
url=self.page_queue.get()
self.parse_page(url)
def parse_page(self,url):
ua = UserAgent()
headers = {'User-Agent': ua.random}
response=requests.get(url,headers=headers,timeout=10).content.decode('utf-8')
time.sleep(1)
html=etree.HTML(response)
imgs=html.xpath('//div[@class="page-content text-center"]/div//a/img[@class!="gif"]')
for img in imgs:
img_url=img.get('data-original')
imgname=img.get('alt')
imgname=re.sub(r'[|/<>:*?\"]','_',imgname)
suffix = os.path.splitext(img_url)[1] #获取后缀名
img_name='%s%s'%(imgname,suffix)
self.img_queue.put((img_url,img_name))
#消费者
class Consumer(threading.Thread):
def __init__(self,page_queue,img_queue,*args,**kwargs):
super(Consumer,self).__init__(*args,**kwargs)
self.page_queue=page_queue
self.img_queue=img_queue
def run(self):
opener = request.build_opener()
opener.addheaders = [('User-Agent',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
request.install_opener(opener)
while True:
if self.img_queue.empty() and self.page_queue.empty():
break
img_url,img_name=self.img_queue.get()
try:
request.urlretrieve(img_url, '%s%s' % ('doutula2/', img_name))
print("图片下载完成!")
except:
pass
def main():
page_queue=Queue(100)
img_queue=Queue(10000)
for i in range(1,101):
url="http://www.doutula.com/photo/list/?page=%d"% i
print(url)
page_queue.put(url)
for x in range(8):
t=Procuder(page_queue,img_queue)
t.start()
for x in range(5):
t=Consumer(page_queue,img_queue)
t.start()
if __name__=='__main__':
main()
多线程版本使用了while循环,同时使用了if判断,break退出循环,不过存在问题,当翻页数过少,比如3的还是会跳过图片下载!
- 最新机器学习必备十大入门算法!都在这里了
- ASP.NET MVC的Razor引擎:IoC在View激活过程中的应用
- 深度学习笔记:深度学习在计算机视觉的应用
- 快速添加永久存储到到Minishift / CDK 3
- 张小龙发布2018微信全新计划(内附演讲全文)
- 使用JClouds在Java中获取和发布云服务器
- 利用ASP.NET SiteMap生成与Bootstrap"兼容"菜单
- 埃隆·马斯克强烈推荐的5本书,看完之后他开始改变世界
- 算法:AOE网(Activity On edge Network)与关键路径简介
- ASP.NET Core的配置(4):多样性的配置来源[中篇]
- ASP.NET MVC的Razor引擎:RazorViewEngine
- 算法:求解AOE网的关键路径
- 编程小技巧:多态原理
- ASP.NET Core的配置(4):多样性的配置来源[下篇]
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Hive on Spark参数调优姿势小结
- 想跨端开发小程序?这个最流行的跨端框架一定要学习!
- 1分钟搞定 Nginx 版本的平滑升级与回滚
- 详解:如何在uni-app中选择一个合适的UI组件库
- Python处理HTTP请求之requests指北
- 习题 3: 数字和数学计算
- Python桌面图形程序美化的方法论
- Windows 入侵痕迹清理技巧
- Linux 入侵痕迹清理技巧
- 面经手册 · 第10篇《扫盲java.util.Collections工具包,学习排序、二分、洗牌、旋转算法》
- 一次代码评审,差点过不了试用期!
- 利用ELK分析Nginx日志生产实战(高清多图)
- 习题 4:变量和命名
- 习题 5: 更多的变量和打印
- 习题 6 字符串(string)和文本