利用python多线程爬取妹子图

一、妹子图爬取前分析

1、首先我们还是要简单分析一下妹子图,第一就是要知道爬取网站的url,这里妹子图的url就是它https://www.mzitu.com/
2、接着我们分析妹子图的请求方式,看看它以什么方式渲染。这里妹子图只是利用了传统的网页(没有使用Ajax或js)。

利用python多线程爬取妹子图_第1张图片
image.png

3、接着点击进入页面,连续点击下一页,发现url存在一定规律,如图,url最后4会变成5、6、7
利用python多线程爬取妹子图_第2张图片
image.png

4、再查看具体页面的请求方式,这里使用的是GET方法,没有什么特别的。
利用python多线程爬取妹子图_第3张图片
image.png

二、妹子图爬取代码布局

1、大体了解妹子图使用的技术后,我们就可以开始尝试爬取妹子图了,首先我们爬取首页面所有的”妹子“url

            response = requests.get(url, headers=headers)
            #从内容中分析出的响应内容编码方式进行编码
            response.encoding = response.apparent_encoding
            tree = etree.HTML(response.text)
            page = tree.xpath('//div[@class="pagenavi"]//span/text()')[-2]
            title = tree.xpath('//*[@class="main-title"]/text()')[0]
            for i in range(1, int(page) + 1):
                # url格式化后再进行重构
                new_url = url + '/{}'.format(i)
                rep = requests.get(new_url, headers=headers)
                html = etree.HTML(rep.text)
                src = html.xpath('//div[@class="main-image"]//img/@src')
                pic_src.append(src)
            self.img_queue.put((title, pic_src))

2、接着再进入特定的”妹子“页面,再进行具体的”妹子图片“爬取,获取到图片的地址信息

        response = requests.get(url, headers=headers)
        response.encoding = response.apparent_encoding
        tree = etree.HTML(response.text)
        url_lists = tree.xpath('//div[@class="postlist"]//span/a/@href')
        return url_lists

3、最后再将获得的图片地址下载保存在本地即可

            if self.page_queue.empty() and self.img_queue.empty():
                return
            list = self.img_queue.get(block=True)
            title, pic_srcs = list
            root = "C:\\meizitu\\"
            num = len(pic_srcs)
            pic_title = '{}【共{}页】'.format(title, num)
            dirname = root + pic_title
            try:
                #判断系统中是否存在同样名称的目录,若没有的话则创建一个新的目录
                if not os.path.exists(dirname):
                    print('=' * 30 + "正在创建名为《%s》的文件夹" % pic_title)
                    os.mkdir('C:\meizitu\%s' % pic_title)
                else:
                    print("《{}》文件已经存在".format(pic_title))
                i = 1
                for pic_src in pic_srcs:
                    pic_num = pic_src[0].split('/')[-1]
                    pic = requests.get(pic_src, headers=headers).content
                    pic_name = dirname + '/' + pic_num
                    #判断是否存在同样名称的图片,没有的话则下载
                    if not os.path.exists(pic_name):
                        print("正在《%s》文件中下载%s张图片" % (pic_title, i))
                        #图片要用bite的形式进行保存
                        with open(pic_name, 'wb') as fb:
                            fb.write(pic)
                            print("成功保存图片")
                    else:
                        print("{}图片已存在".format(pic_title + pic_num))
                    i = i + 1

注意:妹子图具有简单的反爬虫设置,我们需要设置好请求头,否则下载下来的图片为空。

三、技术使用

上篇文章中采用单线程的方式爬取了妹子图,效率实在是太低,本次将采用多线程的方式爬取妹子图,并对妹子进行分类保存。

四、代码实现

import requests
from lxml import etree
import os
import time
import threading
import re
from queue import Queue

headers = {
        'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36',
        'cookie': 'Hm_lvt_dbc355aef238b6c32b43eacbbf161c3c=1528013189,1528123045,1528211821,1528376611',
        'referer': 'https://www.mzitu.com/'
    }
class Producer(threading.Thread):
    def __init__(self,page_queue,img_queue,*args,**kwargs):
        super(Producer,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.get_img_src(url)


    def get_img_src(self,url):
        try:
            pic_src = []
            response = requests.get(url, headers=headers)
            #从内容中分析出的响应内容编码方式进行编码
            response.encoding = response.apparent_encoding
            tree = etree.HTML(response.text)
            page = tree.xpath('//div[@class="pagenavi"]//span/text()')[-2]
            title = tree.xpath('//*[@class="main-title"]/text()')[0]
            for i in range(1, int(page) + 1):
                # url格式化后再进行重构
                new_url = url + '/{}'.format(i)
                rep = requests.get(new_url, headers=headers)
                rep.encoding = rep.apparent_encoding
                html = etree.HTML(rep.text)
                src = html.xpath('//div[@class="main-image"]//img/@src')[0]
                pic_src.append(src)
            print(title,pic_src)
            self.img_queue.put((title, pic_src))
        except:
            print("爬取妹子图片地址失败")


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):
        while True:
            if self.page_queue.empty() and self.img_queue.empty():
                return
            list = self.img_queue.get(block=True)
            title, pic_srcs = list
            root = "C:\\meizitu\\"
            num = len(pic_srcs)
            pic_title = '{}【共{}页】'.format(title, num)
            dirname = root + pic_title
            try:
                #判断系统中是否存在同样名称的目录,若没有的话则创建一个新的目录
                if not os.path.exists(dirname):
                    print('=' * 30 + "正在创建名为《%s》的文件夹" % pic_title)
                    os.mkdir('C:\meizitu\%s' % pic_title)
                else:
                    print("《{}》文件已经存在".format(pic_title))
                i = 1
                for pic_src in pic_srcs:
                    pic_num = pic_src.split('/')[-1]
                    pic = requests.get(pic_src, headers=headers).content
                    pic_name = dirname + '/' + pic_num
                    #判断是否存在同样名称的图片,没有的话则下载
                    if not os.path.exists(pic_name):
                        print("正在《%s》文件中下载%s张图片" % (pic_title, i))
                        #图片要用bite的形式进行保存
                        with open(pic_name, 'wb') as fb:
                            fb.write(pic)
                            print("成功保存图片")
                    else:
                        print("{}图片已存在".format(pic_title + pic_num))
                    i = i + 1
            except:
                print('{}爬取失败'.format(dirname))


def get_all_host_url(url):
    try:
        response = requests.get(url, headers=headers)
        response.encoding = response.apparent_encoding
        tree = etree.HTML(response.text)
        url_lists = tree.xpath('//div[@class="postlist"]//span/a/@href')
        return url_lists
    except:
        print("爬取首页妹子地址失败")


if __name__ == '__main__':
    base_url = 'https://www.mzitu.com/page/{}/'
    page_queue = Queue(100)
    img_queue = Queue(500)
    for i in range(1,4):
        url = base_url.format(i)
        url_lists = get_all_host_url(url)
        print("第%d页的图片地址%s"%(i,url_lists))
        # time.sleep(1)
        for url_list in url_lists:
            page_queue.put(url_list)
    for x in range(10):
        t = Producer(page_queue,img_queue)
        t.start()
    for x in range(10):
        t = Consumer(page_queue,img_queue)
        t.start()


五、效果图

利用python多线程爬取妹子图_第4张图片
image.png

你可能感兴趣的:(利用python多线程爬取妹子图)