在图片网站爬取图片时候,我们需要取得具体每张图片的url地址,然后下载到电脑保存下来。这其中,对时间消耗最多的步骤是保存图片到本地硬盘,机械硬盘的读写性能速度较慢。如果采取单线程单进程的话,在读写的同时没法进行其他的操作,只能等待,浪费了性能。
对单个存有图片的页面而言,如果可以采取多线程的话,在写入图片的同时还能去请求新的图片地址保存到列表将会更合理的利用时间。因为图片网站,图片存放在很多页面里,所以对多个存有图片的页面而言采取 多进程,同时对多个有图片的页面进行爬取任务。
至于你要爬取什么样的图片网站, 我不得而知,不同网站展示图片界面不同或许与我的有差异但主体思路就这样。
接下来上代码:
import requests ,time,threading
from lxml.html import etree
from fake_useragent import UserAgent
from multiprocessing import Pool
#得到自己爬取页网址
def get_Url(P):
Url='保密'.format(P)
return Url
#得到10个尤物的名字
def get_names(Url):
all_names=[]
header = {'User-Agent': UserAgent().chrome}
response = requests.get(url=Url, headers=header)
response.encoding = 'GB18030'
e = etree.HTML(response.text)
picture_name = e.xpath('//h2/a')
for k in range(10):
all_names.append(picture_name[k].text)
return all_names
#得到第i个尤物的名字 i 0 9
def get_i_name(all_names,i):
i_name=all_names[i]
return i_name
#得到10个尤物的首网址
def get_url(Url):
all_urls=[]
header = {'User-Agent' : UserAgent().chrome}
response=requests.get(url=Url,headers=header)
response.encoding='GB18030'
e=etree.HTML(response.text)
url=e.xpath('//h2//@href')
for k in range(10):
new_url = 'https://qqr57.com' + url[k]
all_urls.append(new_url)
return all_urls
#得到第i个尤物的首地址
def get_i_url(all_urls,i):
i_url=all_urls[i]
return i_url
#得到第i个尤物存在图片的地址
def i_girl_pictures_urls(i_url):
mod_page_urls=[]
header = {'User-Agent': UserAgent().chrome}
response = requests.get(url=i_url, headers=header)
response.encoding = 'GB18030'
e = etree.HTML(response.text)
next_page = (e.xpath('//li[@class="next-page"]/a'))[0].text
j = 1
#空列表=false
while next_page :
j = j + 1
last_page = i_url.replace('.html', '_' + str(j) + '.html')
new_new_url = last_page
header = {'User-Agent': UserAgent().chrome}
response = requests.get(url=new_new_url, headers=header)
response.encoding = 'GB18030'
e = etree.HTML(response.text)
# # time.sleep(0.05)
next_page = (e.xpath('//li[@class="next-page"]/a'))
# print(next_page)
mod_page_urls.append(new_new_url)
mod_page_urls.append(i_url)
return mod_page_urls
#得到第i尤物所有图片地址
def girl_jpg_urls(mod_page_urls):
girl_pictures_urls=[]
for a in range(len(mod_page_urls)):
# 一只尤物某一个网页的图片链接地址
time.sleep(0.1)
girl_urls = mod_page_urls[a]
# 一只尤物的所有图片地址
header = {'User-Agent': UserAgent().chrome}
response = requests.get(url=girl_urls, headers=header)
response.encoding = 'GB18030'
e = etree.HTML(response.text)
girl_pictures_url = (e.xpath('//article[@class="article-content"]/p/img/@src'))
girl_pictures_urls+=(girl_pictures_url)
print(girl_pictures_urls)
return girl_pictures_urls
#根据所有图片地址 下载第i个尤物的图片
def save_imgs(girl_pictures_urls,i_name):
x = len(girl_pictures_urls)
for b in range(x):
r = requests.get(url=girl_pictures_urls[b])
time.sleep(0.2)
print("正在爬取尤物" + i_name + str(b) + '进度:' + str(100 * (b + 1) / x) + '%')
with open('保密/{}.jpg'.format(i_name + str(b)), 'wb') as f:
f.write(r.content)
#多线程下载单页的所有图片
def thread(P):
threads = []
Url=get_Url(P)
all_names=get_names(Url)
all_urls=get_url(Url)
for i in range(10):
i_name = get_i_name(all_names, i)
i_url = get_i_url(all_urls, i)
mod_page_urls = i_girl_pictures_urls(i_url)
girl_pictures_urls = girl_jpg_urls(mod_page_urls)
# save_imgs(girl_pictures_urls,i_name)
t = threading.Thread(target=save_imgs,args=(girl_pictures_urls,i_name))
threads.append(t)
for i in threads:
i.start()
for i in threads:
i.join()
#多进程请求不同的页面
def process(P):
pool = Pool(processes=4) #定义一个进程池,最大进程数为4,默认大小为CPU核数
for i in range(P):
pool.apply_async(func=thread, args=(i,))
pool.close()
pool.join()
# 主程序
if __name__ == '__main__':
P=int(input('输入爬取的页面数量:'))
start=time.time()
process(P)
end=time.time()
print(str(end-start))
上效果图:
共有634张图片,
用时701秒,
单张图片用时约1.1秒
速度比较慢。这是因为,我只爬取得一个页面做了个示范,只体现出了多线程优势,多进程的优势没有体现出来。
再来一个示范:
这次我爬取了2694张图片 ,用时895秒,单张图片用时约0.3秒。因为我这次爬取的页数为4,CPU核数也为4,多进程的优势正好可以利用起来。
当页面数越多,图片数越多,节省的时间也越多。看着数据不断爬取下来的过程,很舒服啊
最终我一共爬取了4万多张图片。用时没统计,感觉不到 半小时。