斗图狂魔必备沙雕表情包,python多线程爬取斗图啦表情图片

时间:2022-07-22
本文章向大家介绍斗图狂魔必备沙雕表情包,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的还是会跳过图片下载!