python多线程爬取妹子图
- python使用版本:
3.7 - 目的:
自己选择下载目录,逐个将主题图片保存到选定目录下。 - 效果:
一秒钟左右下载一张图片,下了七八十组图片暂时没什么问题,不放心的话,可以速度再放慢点。 - 注意:
网页的请求头’headers’要加上’referer’参数,不然页面内容无法正常返回。
xpath返回的是列表,使用切片赋值。 - 小坑:
直接用xpath获取的主题名字创建文件夹或者文件命名,可能会出错,会出现非法字符,比如’?'等,用正则处理下。 - 改进:
针对每一个图片创建url队列,再单独调用线程下载,看起来可能会舒心点。(暂时就这样吧)
代码块如下,初次学习,还请各位多多指教:
#encoding=utf_8
import os
import requests
from lxml import etree
from queue import Queue
import re
import time
import tkinter
from tkinter import filedialog
from threading import Thread
class BelleSpider():
def __init__(self):
#用于存放每一个人物图片theme的url队列
self.q = Queue()
self.pre_url = 'https://www.mzitu.com/xinggan/page/'
self.headers = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
'referer':'https://www.mzitu.com/xinggan/'}
def get_theme(self,start_page=1):
i = start_page
while True:
page = str(i)
print('{0:*^50}'.format('正在写入第{}页url地址'.format(i)))
response = requests.get(self.pre_url + page, headers=self.headers)
print(response.url)
html_content = response.content.decode()
tree = etree.HTML(html_content)
a = tree.xpath("//ul[@id='pins']/li/span[1]/a")
for each in a:
theme_url = each.xpath('./@href')[0]
theme_text = each.xpath('./text()')[0]
'''put,block参数默认为True,如果队列满了,则会阻塞等待。'''
self.q.put((theme_text,theme_url))
time.sleep(2)
'''有下一页,就继续抓取图片主题url'''
if html_content.find('下一页') > 0 :
i += 1
else:
print('最后一页theme主题url已经抓取完了~')
break
def download(self,start_page=1):
global download_directory
while True:
print('准备获取队列大小:{}'.format(self.q.qsize()))
if not self.q.empty():
'''默认block=True,队列为空,就会阻塞,直到有数据可以取出。'''
get = self.q.get()
self.q.task_done()
the_theme,the_url = get
'''文件命名规则原因,文件名剔除一些特殊的符号'''
regexp_bat = re.compile('[\??\.。!!]*')
theme = regexp_bat.sub('',the_theme)
url = the_url
mkdir = os.path.join(download_directory , theme)
print('theme文件名称为:{}',format(mkdir))
if not os.path.exists(mkdir):
'''如果没有这个目录,则创建该目录'''
os.mkdir(mkdir)
'''定义该目录下载初始页:1'''
picture_page = start_page
while True:
the_picture_page_content = requests.get(url=url+'/'+str(picture_page),
headers=self.headers).content.decode()
tree = etree.HTML(the_picture_page_content)
'''xpath提取图片下载地址'''
the_download_url = tree.xpath("//div[@class='main-image']/p/a/img/@src")[0]
response = requests.get(url=the_download_url,headers=self.headers)
pic_name = '{}/{}-{}.jpg'.format(mkdir,theme,picture_page)
'''保存图片到目录'''
with open(pic_name, 'wb') as f:
f.write(response.content)
print('已经保存好图片{}-{}......'.format(theme,picture_page))
time.sleep(1.5)
'''下一页'''
picture_page += 1
'''如果有下一组,表示这组图片已经爬完了,这个循环结束。'''
if the_picture_page_content.find('下一组') > 0:
print('当前页已经抓取完毕,请稍等10s钟......')
time.sleep(10)
break
else:
print('该文件已经下载{}'.format(mkdir))
else:
print('队列已经掏空了~~')
break
def main(self,start_time_wait=10,thread_count=3):
t1 = Thread(target=self.get_theme)
t1.start()
print('稍等{}秒,程序即将下载图片...'.format(start_time_wait))
'''先等待若干秒,防止队列为空,t2线程q.empty直接跳出循环结束线程。'''
time.sleep(start_time_wait)
for i in range(thread_count):
t2 = Thread(target=self.download)
t2.start()
'''线程阻塞,直接队列所在线程运行完毕,主线程才往下走。'''
self.q.join()
print('所有文件已经下载完毕!')
if __name__ == '__main__':
win = tkinter.Tk()
'''调用窗口,选择下载目录'''
download_directory = filedialog.askdirectory()
m = BelleSpider()
m.main(start_time_wait=5)
print('Done!')
'''结束Tk'''
win.mainloop()