项目说明
之前无意间发现的壁纸网站,都是无水印且分辨率很高的壁纸,但是如果要一张一张保存显得麻烦,如果我能批量下载壁纸,就能很快筛选出自己想要保留下的壁纸。
项目结构
项目功能
1.两种模式
搜索(指定关键词,建议用英文)和排行(指定日期,排序和其他属性筛选指定区间的壁纸)。
2.限制类型选择
色色(限定类型输入0)与正常模式(限定类型输入除了0以外的任何数字)。
3.如何实现自由选择限定词的?
答:建立了一个字典,实现了字符串之间的一个映射。核心代码如下:
# 偏好选择 升降排序默认为降序
@staticmethod
def preference_selection():
print('<---Preference Selection Start--->')
# 偏好数据字典
categories = {'1.General': '100', '2.Anime': '010', '3.People': '001', '4.All': '111'}
sorting = {'1.Relevance': 'relevance', '2.Random': 'random', '3.Date Added': 'date_added',
'4.Views': 'views', '5.Favorites': 'favorites', '6.Toplist': 'toplist', '7.Hot': 'hot'}
topRange = {'1.Last Day': '1d', '2.Last Three Days': '3d', '3.Last Week': '1w', '4.Last Month': '1m',
'5.Last 3 Months': '3m',
'6.Last 6 Months': '6m', '7.Last Year': '1y'}
# 字典转为列表
categories_list = list(categories.items())
sorting_list = list(sorting.items())
topRange_list = list(topRange.items())
# 获取列表长度
categories_len = len(categories_list)
sorting_len = len(sorting_list)
topRange_len = len(topRange_list)
# 获取限制选择
print('purity: only zero.里、other.normal')
n = int(input('请输入限制类型编号:'))
if n == 0:
purity_select = '001'
else:
purity_select = '110'
# 获取种类选择
print('类别: ', end='')
for i in range(categories_len):
if i != categories_len - 1:
print(categories_list[i][0], '、', end='')
else:
print(categories_list[i][0])
m = int(input('请输入类别编号:'))
categories_select = categories_list[m - 1][1]
# 获取类别选择
print('查阅: ', end='')
for i in range(sorting_len):
if i != sorting_len - 1:
print(sorting_list[i][0], '、', end='')
else:
print(sorting_list[i][0])
m = int(input('请输入查阅编号:'))
sorting_select = sorting_list[m - 1][1]
# 获取日期选择
print('日期范围: ', end='')
for i in range(topRange_len):
if i != topRange_len - 1:
print(topRange_list[i][0], '、', end='')
else:
print(topRange_list[i][0])
n = int(input('请输入日期范围编号:'))
topRange_select = topRange_list[n - 1][1]
print('<---Preference Selection End--->\n')
return purity_select, categories_select, sorting_select, topRange_select
重要思路
1.前提摘要
该网站页面会以缩略图的形式呈现壁纸,只有点击缩略图后会弹出专门的壁纸页面。
2.遇到的问题
该网站并不是在壁纸页面直接告诉你具体下载地址,而是一个代表该图片的字符串。我们可以对字符串进行拼接得到具体地址,而问题在于图片格式无法确定,因为图片格式是在缩略图页面中告知的,如果我们直接默认.jpg/.png,就会导致格式不匹配,从而使得图片损坏,即便是修改后缀名也无济于事。
3.解决办法
为了解决问题,我想到了使用二次正则解析(我自己命名的),什么意思呢?第一次正则解析->解析缩略图页面得到图片后缀名(是.jpg还是.png?)和壁纸展示页面地址;第二次正则解析->对第一次得到的壁纸展示页面进行解析得到关键字符串,在进行字符串拼接,在这里将第一次得到的图片后缀名拼接进去,这样我们就得到了真真正正的图片下载地址喽!核心代码如下:
# 能够根据html页信息获取图片的格式为jpg还是png
def get_format(self, url, word, cookies):
# -------------解析preview页图片-------------
# 使用 requests模块得到响应对象
res = requests.get(url, headers=self.headers, cookies=cookies)
# 更改编码格式
res.encoding = "utf-8"
# 得到html网页
html = res.text
# -------------正则解析-------------
pattern = re.compile('<a class="preview".*?href="(.*?)"', re.S)
image_link_list = pattern.findall(html)
print('image_preview_page:\n', image_link_list)
# --------二次正则解析获取图片格式-------
img_format = [] # 定义一个数组来存储,总共有24个格式
count = 1
list = [] # 临时列表
for url in image_link_list:
res = requests.get(url, headers=self.headers, cookies=cookies)
# 更改编码格式
res.encoding = "utf-8"
# 得到html网页
html2 = res.text
# 保存爬取到的html
# self.save_html('./image/image{}.html'.format(count), html2)
# --------解析得到正则表达式对象-------
# r:表示原字符串,这样就可以省略掉转义字符\
pattern = re.compile(r'<div class="scrollbox".*?<img id="wallpaper" .*?src="(.*?)".*?></div>', re.S)
list = re.findall(pattern, html2)
try:
print('\rTips: 正在获取图片格式中... [{:.2f}%] {}/{}'.format(count / 24 * 100, count,
len(image_link_list)), end='')
# print('\nurl:', url)
# print('待追加列表:', list)
# print('待追加格式:', list[0][-3:])
# print('格式列表:', img_format)
# print('====================================================================')
img_format.append(list[0][-3:])
except IndexError:
print('\nTips: (id:{})Error: list为空'.format(count))
pass
count += 1
# --------爬虫睡眠---------
# time.sleep(random.random())
time.sleep(1)
print()
return image_link_list, img_format
# 根据得到的图片格式进行拼接url
def get_image(self, url, word, cookies):
# 返回图片列表和图片格式列表
image_link_list, img_format = self.get_format(url, word, cookies)
# ------先获取到图片格式,然后才能进行url拼接------
image_list = []
# 拼接得到图片页
for i in range(len(image_link_list)): # 有些页内的图片可能不是24张,直接用图片链接列表的长度代替
image_real_url = 'https://w.wallhaven.cc/full/{}/wallhaven-{}.{}'
info_str = image_link_list[i][23:]
# 现在就得到了真正存储图片的url链接,并将其依次加到image_list列表中
image_real_url = image_real_url.format(info_str[0:2], info_str, img_format[i])
image_list.insert(i, image_real_url)
print('\nimage_page:\n', image_list)
# 创建目录,用于保存图片
directory = 'D:/Crawler/{}/'.format(word)
# 如果目录不存在则创建,此方法常用
if not os.path.exists(directory):
os.makedirs(directory)
# 添加计数
i = 0
for image_url in image_list:
filename = '{}{}_{}.{}'.format(directory, word, self.count, img_format[i])
self.save_image(image_url, filename)
self.count += 1
i += 1
# 再次清空存放图片的两个列表,以便下次使用
image_link_list = []
image_list = []
运行结果
源码下载及视频演示
源码下载:百度网盘 请输入提取码
视频演示:[TopWallpaper_Spider v1.1]使用爬虫爬取Topwallpaper网站壁纸_哔哩哔哩_bilibili
心得
这个项目我很早就完成了,我貌似是第一个做该网站爬虫的人,还挺自豪的。但是自己的想法和创意得不到捧场,多少有点闷闷不乐,因此我今天写了这篇博客,希望能够有更多人看见我的文章,在互联网留下自己的一些痕迹。