多线程+正则匹配下载图片(wallheaven图片网站)
1. wallheaven 壁纸网站
这个网站的图片是提供下载的,在壁纸类别之中质量非常高,包括了很多的高清图片。
详细情况可访问其主页页面:wallheaven
2、分析网页架构
1)获取全部页面的地址分析
网页主页地址为:
https://wallhaven.cc/
输入关键词china
进行查询后,地址变为:
https://wallhaven.cc/search?q=china
下滑到第二页之后,地址变为:
https://wallhaven.cc/search?q=china&page=2
那么我们就得到了一个通用的地址访问格式:
https://wallhaven.cc/search?q={}&page={}
其中两个中括号之中分别填写关键词和页数
2)获取全部图片的地质
查看一张图片的url地址

https://th.wallhaven.cc/small/mp/mp3dwm.jpg
但是点开图片再单独查看图片可见其地址为:
https://w.wallhaven.cc/full/mp/wallhaven-mp3dwm.jpg
对比前后两张图片,可以明显地发现首页展示的图片画质非常差,而且经过压缩之后大小变形了,用来做壁纸或者其他用途都很有限。所有我们通向希望得到详细页面中的高清页面。我们至此有两种方案可以获取得到图片的地址:
- 从首页进入图片页面,在图片页面获得图片下载地址
- 从首页获得低清晰度图片下载地址,经过地址重组获得高清图片的下载地址
这里我选择第二种方法,以便捡一捡长时间不用的正则表达
3、编码实现
1) 导入相关函数库
import os
import requests
import redis
from lxml import etree
import urllib.request
import time
import threading
from queue import Queue
import re
2) 我后面打算使用redis作为中间件保存url等信息,暂时还没有使用,先定义好(可略过)
pool = redis.ConnectionPool(host='localhost',port=6379,decode_responses=True)
r = redis.Redis(connection_pool=pool)
print(r.ping())
3)主要函数及爬取过程
注意:
- headers 中的内容根据自己的情况进行填写
- Producer类:获取全部的img地址
- consumer类:下载img
- 我这里使用的关键词是’anime’,可以通过input来进行交互下载
- 如果有什么错误或者认为不太正确的地方请联系我
Headers = {
'authority': 'wallhaven.cc',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'cookie': '', # 请写上自己的
'referer': 'https://wallhaven.cc/',
'user-agent': '' # 请修改为自己的
}
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
page_url = self.page_queue.get()
page_text = self.deal_url(page_url)
self.parse_indexPage(page_text)
def deal_url(self,url):
response = requests.get(url,headers=Headers)
response.encoding= response.apparent_encoding
return response.text
def parse_indexPage(self,text):
html = etree.HTML(text)
wallpaper_urls = html.xpath("//img[@alt='loading']/@data-src")
for url in wallpaper_urls:
url = url.replace('th','w',1) # 替换第一个th为w
url = url.replace('small','full') # 替换small为full
last_urlTail = re.search(r'[^/]+(?!.*/)',url).group() #正则获取url最后一个/后的内容
new_urlTail = 'wallhaven-'+last_urlTail
url = url.replace(last_urlTail,new_urlTail) #重构网址
self.img_queue.put((new_urlTail,url))
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.img_queue.empty() and self.page_queue.empty():
break
img_name,img_url = self.img_queue.get()
self.save_img(img_name,img_url)
def save_img(self,img_name,img_url):
root= './3_figure/'
path = root+img_name
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
read_figure = requests.get(img_url)
with open(path,'wb')as f:
f.write(read_figure.content)
f.close()
print(path+" save ok!")
else:
print('文件已保存')
except:
print("文件爬取失败")
def main():
base_url = 'https://wallhaven.cc/search?q={}&page={}'
# keyword = input("please input the keyword")
keyword = 'anime'
page_queue = Queue(20)
img_queue = Queue(200)
page_num = 10
for x in range(1,page_num+1):
url = base_url.format(keyword,x)
page_queue.put(url)
print(url)
for x in range(5):
t = Producer(page_queue,img_queue)
t.start()
for x in range(5):
t = Consumer(page_queue,img_queue)
t.start()
if __name__ == '__main__':
main()
4、结果视图
我下载了10页的图片,每页24张图片,共计240张:
打开其中的一张图片:
看起来画质还不错。