一、妹子图爬取前分析
1、首先我们还是要简单分析一下妹子图,第一就是要知道爬取网站的url,这里妹子图的url就是它https://www.mzitu.com/
2、接着我们分析妹子图的请求方式,看看它以什么方式渲染。这里妹子图只是利用了传统的网页(没有使用Ajax或js)。
3、接着点击进入页面,连续点击下一页,发现url存在一定规律,如图,url最后4会变成5、6、7
4、再查看具体页面的请求方式,这里使用的是GET方法,没有什么特别的。
二、妹子图爬取代码布局
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()