斗图高手教你用Python批量爬取表情包

前言

昨天跟小伙伴斗图,关于斗图这件事,我表示我从来没有输过。至于为什么不会输,这些都是男人的秘密,今天我想把这个小技

巧告诉大家。学会了记得挑战你最好的朋友,打赌让他输了请你吃大西瓜…
在这里插入图片描述

1、介绍

•平台:斗图啦

•语言:python

•技术:python多线程、python安全队列、python之Xpath、正则、request

以上我们使用的技术,都是之前整理过的对不对,那么我们就根据之前的学习内容来进行爬取斗图表情包吧。

在这里插入图片描述

2、python爬取流程梳理

我们刚开始学习的时候,是不是每次都需要梳理下爬取的流程呢,那么这次咱们还是和之前一样,首先我们需要找到我们爬取的平台的网址是什么:
https://dou.yuanmazg.com/doutu?page=1

访问这个界面之后,我们可以看到如下显示的内容:

在这里插入图片描述

然后我们往下滑之后,可以看到这里一共有1500+的页面,那么我们现在爬取前50页的内容吧,大概流程我觉得应该如下哈:

1.获取每个页面的url;


2.将获取到的url放置Queue中;


3.从Queue中获取一个Url,使用requests获取内容,使用xpath获取取该Url中每一个图片的Url;


4.然后将每个图片中的Url放入到另一个Queue中;


5.然后再从第二个Queue中获取图片的url;


6.根据Queue来下载并保存即可;


7.以上步骤我们使用多线程+Queue的形式来进行。

在这里插入图片描述

3、python爬取图片

3.1 框架

老样子,首先我们简简单单写一个框架;

import threading


class Producter(threading.Thread):
    pass


class Consumer(threading.Thread):
    pass


def main():
    pass


if __name__ == '__main__':
    main()

然后我们一步一步进行;

在这里插入图片描述

3.2 初步获取页面有效信息

python学习交流Q群:906715085###
import requests
from lxml import etree

Url = 'https://dou.yuanmazg.com/doutu?page=1'
Header = {
    
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}
Page_get = requests.get(url=Url, headers=Header)
Page_content = Page_get.text
Page_message = etree.HTML(Page_content)
Page_div = Page_message.xpath('//div[@class="page-content"]')[0]
Page_div = etree.tostring(Page_div, pretty_print=True, method='html').decode('utf-8')
print(Page_div)


3.3  提取每一个图片的url和name
import requests
from lxml import etree

Url = 'https://dou.yuanmazg.com/doutu?page=1'
Header = {
    
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}
Page_get = requests.get(url=Url, headers=Header)
Page_content = Page_get.text
Page_message = etree.HTML(Page_content)
Page_div = Page_message.xpath('//div[@class="page-content"]//a//img')
# Page_div = etree.tostring(Page_div, pretty_print=True, method='html').decode('utf-8')
# print(Page_div)
for i in Page_div:
    # print(etree.tostring(i, pretty_print=True, method='html').decode('utf-8'))
    Page_url = 'https://dou.yuanmazg.com' + i.xpath("@data-original")[0]
    Page_name = i.xpath("@alt")[0]
    print(Page_url)
    print(Page_name)

输出结果如下:
在这里插入图片描述

在这里插入图片描述

3.4 优化名字

我们可以看到我们获取的图片的名字中有特殊符号,但是我们的电脑上文件名字是不可以出现特殊符号的,那么我们是不是就需

要把名字给他处理一下呢,优化走起,优化之后的代码如下:

import requests
from lxml import etree
import re

Url = 'https://dou.yuanmazg.com/doutu?page=1'
Header = {
    
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}
Page_get = requests.get(url=Url, headers=Header)
Page_content = Page_get.text
Page_message = etree.HTML(Page_content)
Page_div = Page_message.xpath('//div[@class="page-content"]//a//img')
# Page_div = etree.tostring(Page_div, pretty_print=True, method='html').decode('utf-8')
# print(Page_div)
for i in Page_div:
    # print(etree.tostring(i, pretty_print=True, method='html').decode('utf-8'))
    Page_url = 'https://dou.yuanmazg.com' + i.xpath("@data-original")[0]
    Page_name = i.xpath("@alt")[0]
    Page_name = re.sub(r'[,。??,/\\·\*\ ]', '', Page_name)
    print(Page_url)
    print(Page_name)

随之我们又发现了另一个问题,那就是有些图片他是没有添加描述的,也就是无法获取该图片的名字,那么我们就随机给他一个

名字吧;

import requests
from lxml import etree
import re
import random

Url = 'https://dou.yuanmazg.com/doutu?page=1'
Header = {
    
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}
Page_get = requests.get(url=Url, headers=Header)
Page_content = Page_get.text
Page_message = etree.HTML(Page_content)
Page_div = Page_message.xpath('//div[@class="page-content"]//a//img')
# Page_div = etree.tostring(Page_div, pretty_print=True, method='html').decode('utf-8')
# print(Page_div)
for i in Page_div:
    # print(etree.tostring(i, pretty_print=True, method='html').decode('utf-8'))
    Page_url = 'https://dou.yuanmazg.com' + i.xpath("@data-original")[0]
    Page_name = i.xpath("@alt")[0]
    Page_name = re.sub(r'[,。??,/\\·\*\ ]', '', Page_name)
    if Page_name == "":
        Page_name = str(random.random())
    print(Page_url)
    print(Page_name)

到这里是不是名字这个事儿就完事儿了呢,当然不了,想一下,我们在电脑上创建文件的时候是不是还需要后缀名呢,那我们就

应该也把后缀名获取一下子,再次优化之后,代码如下:

import requests
from lxml import etree
import re
import random
import os

Url = 'https://dou.yuanmazg.com/doutu?page=1'
Header = {
    
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}
Page_get = requests.get(url=Url, headers=Header)
Page_content = Page_get.text
Page_message = etree.HTML(Page_content)
Page_div = Page_message.xpath('//div[@class="page-content"]//a//img')
# Page_div = etree.tostring(Page_div, pretty_print=True, method='html').decode('utf-8')
# print(Page_div)
for i in Page_div:
    # print(etree.tostring(i, pretty_print=True, method='html').decode('utf-8'))
    Page_url = 'https://dou.yuanmazg.com' + i.xpath("@data-original")[0]
    Suffix = os.path.splitext(Page_url)[1]
    Page_name = i.xpath("@alt")[0]
    Page_name = re.sub(r'[,。??,/\\·\*\ ]', '', Page_name)
    if Page_name == "":
        Page_name = str(random.random()) + Suffix
    else:
        Page_name = Page_name + Suffix
    print(Page_url)
    print(Page_name)

运行之后结果如下:

在这里插入图片描述

好的,这样子的话我们就成功的使用python获取了每一个页面中每一个图片的地址和名字

在这里插入图片描述

3.5 下载

当我们获取到了图片的下载地址,以及图片名字之后,我们就可以进行下载了,那么我们的代码就变成了下面的内容:

python学习交流Q群:906715085####
import requests
from lxml import etree
import re
import random
import os
from urllib import request

Url = 'https://dou.yuanmazg.com/doutu?page=1'
Header = {
    
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}
Page_get = requests.get(url=Url, headers=Header)
Page_content = Page_get.text
Page_message = etree.HTML(Page_content)
Page_div = Page_message.xpath('//div[@class="page-content"]//a//img')
# Page_div = etree.tostring(Page_div, pretty_print=True, method='html').decode('utf-8')
# print(Page_div)
for i in Page_div:
    # print(etree.tostring(i, pretty_print=True, method='html').decode('utf-8'))
    Page_url = 'https://dou.yuanmazg.com' + i.xpath("@data-original")[0]
    Suffix = os.path.splitext(Page_url)[1]
    Page_name = i.xpath("@alt")[0]
    Page_name = re.sub(r'[,。??,/\\·\*\ ]', '', Page_name)
    if Page_name == "":
        Page_name = str(random.random()) + Suffix
    else:
        Page_name = Page_name + Suffix
    # print(Page_url)
    # print(Page_name)
    request.urlretrieve(Page_url, 'doutula/' + Page_name)
    print("{}下载完成了~~~".format(Page_name))

运行之后会输出哪个下载完成了,如下:
我不想做个肤浅的人.jpg下载完成了~~~
我黑点没事你别绿了.jpg下载完成了~~~
我不想白活一辈子.jpg下载完成了~~~
我妈肚子里有墨水.jpg下载完成了~~~
劳资之前白的后来帅炸了炸黑了.jpg下载完成了~~~
我为了暗中保护你.jpg下载完成了~~~
我晒你家太阳了.jpg下载完成了~~~
黑夜给了我一双黑色的眼睛可我却一不小心按了全选!.jpg下载完成了~~~
— 省略部分内容—

而且会在doutula这个文件夹下将下载的文件进行保存,如下图:

在这里插入图片描述

3.6 添加安全队列和多线程

为什么要使用多线程和安全队列都清楚吧,就是为了速度和数据的准确性啊。

既然我们实现了一个页面中的表情包下载,那么我们是不是只需要稍微改动一下,多启动几个线程,添加几个循环,就能搞定了

呢,经过我们的代码优化之后,成了下面的样子:

python学习交流Q群:906715085####
import requests
from lxml import etree
import re
import random
import os
from urllib import request
from queue import Queue
import threading
import time


class Producer(threading.Thread):
    Header = {
    
    
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}

    def __init__(self, Page_queue, Photo_queue, *args, **kwargs):
        super(Producer, self).__init__(*args, **kwargs)
        self.Page_queue = Page_queue
        self.Photo_queue = Photo_queue

    def run(self):
        while True:
            if self.Page_queue.empty():
                break
            url = self.Page_queue.get()
            self.photo_down(url)

    def photo_down(self, url):
        Page_get = requests.get(url=url, headers=self.Header)
        Page_content = Page_get.text
        Page_message = etree.HTML(Page_content)
        Page_div = Page_message.xpath('//div[@class="page-content"]//a//img')
        for i in Page_div:
            Page_url = 'https://dou.yuanmazg.com' + i.xpath("@data-original")[0]
            Suffix = os.path.splitext(Page_url)[1]
            Page_name = i.xpath("@alt")[0]
            Page_name = re.sub(r'[,。??,/\\·\*\ ]', '', Page_name)
            if Page_name == "":
                Page_name = str(random.random()) + Suffix
            else:
                Page_name = Page_name + Suffix
            self.Photo_queue.put((Page_url, 'doutula/' + Page_name))


class Consumer(threading.Thread):
    def __init__(self, Page_queue, Photo_queue, *args, **kwargs):
        super(Consumer, self).__init__(*args, **kwargs)
        self.Page_queue = Page_queue
        self.Photo_queue = Photo_queue

    def run(self):
        while True:
            if self.Page_queue.empty() is True and self.Photo_queue.empty() is True:
                break
            else:
                img_url, img_name = self.Photo_queue.get()
                print(img_url)
                print(img_name)
                request.urlretrieve(img_url, img_name)


def main():
    Page_queue = Queue(maxsize=100)
    Photo_queue = Queue(maxsize=2000)
    for i in range(1, 51):  # 下载的页数
        Page_url = 'https://dou.yuanmazg.com/doutu?page={}'.format(i)
        Page_queue.put(Page_url)

    for i in range(5):  # 启动5个消费者
        t1 = Producer(Page_queue, Photo_queue)
        t1.start()

    time.sleep(5)  # 停留5秒是为了避免消费者的第一个页面都没请求下来的时候,生产者就直接判断无数据,从而自行终止程序。
    for i in range(4):  # 启动5个生产者
        t2 = Consumer(Page_queue, Photo_queue)
        t2.start()


if __name__ == '__main__':
    main()

经过实验之后,下载速度快多了,结果如下:

在这里插入图片描述

这样子我们就可以实现多线程下载斗图表情包,下一次和朋友斗图,再也不怕没有表情包了。

猜你喜欢

转载自blog.csdn.net/xff123456_/article/details/125146138