爬虫简单实践之 wallhaven

前言

闲来无事,简单写了一个爬虫,功能也很简单,就是爬取 wallhaven 上的图片。

阅读之前,如果你对爬虫感到陌生,你也可以点击 这里 在我的另一篇文章中快速、了解掌握爬虫。

爬虫思路

根据 url 的规律指定爬取页面

简单观察 url 便可以发现,规律很简单,只需要指定页面即可。

1
https://wallhaven.cc/toplist?page=

解析 html 获得当前页面所有图片 url

接下来我们观察 html 结构

很显然,我们需要的链接在一个 a 标签中,且 class=preview,那么,我们便可以通过 find_all('a', class_='preview') 命令找到所有的 url。

注意上面的另一个 url 是小图,如果你不关心图片尺寸,那么可以直接使用它。

进入图片之后,再次解析 html 获得原始图片的 url

得到图片的 url 之后,我们再次 get ,进入图片页面,再次解析 html,观察结构

同样的,我们发现原始图片的链接在一个 img 标签中,且 id=wallpaper,链接在 src 之中,用类似的方法使用 BeautifulSoup 进行解析,这样,我们就得到了图片的 url。

另外,我们可以用 data-wallpaper-id 作为标识符,或者给图片命令。

get 原始图片的 url 并保存到本地

得到了原始图片的 url 后,我们便可以再次 get 得到图片数据,然后写入文件即可,类似这样:

1
2
3
data = requests.get(url, headers=headers)
with open(img_name, 'wb') as f:
f.write(data.content)

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
'''
Descroption: wallhaven 爬虫
Author: EmoryHuang
Date: 2021-08-25 11:10:33
Method:
1. 根据 url 的规律指定爬取页面
2. 解析 html 获得当前页面所有图片 url
3. 进入图片之后,再次解析 html 获得原始图片的 url
4. get 原始图片的 url 并保存到本地
'''

import os
import sys
import time
import requests
from typing import List
from bs4 import BeautifulSoup


# 获得当前页面所有图片 url
def get_page_url(page: str) -> List[str]:
'''
:description: 获得当前页面所有图片 url
:param {str} page 指定页号
:return {List[str]} 返回当前页面的图片 url 列表
'''
headers = {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Connection': 'keep-alive'
}
url = 'https://wallhaven.cc/toplist?page=' + str(page)
r = requests.get(url, headers=headers, timeout=5)
soup = BeautifulSoup(r.text, 'lxml')
page_url = []
for link in soup.find_all('a', class_='preview'):
page_url.append(link.get('href'))
return page_url


# 图片下载到本地
def download(path: str, start: int = 1, cnt: int = 5) -> None:
'''
:description: 图片下载到本地
:param {str} path 文件存储路径
:param {int} start 起始页号,默认为1
:param {int} cnt 爬取页数,默认为5
:return {*}
'''
print('开始爬取 wallhaven/toplist 图片第' + str(start) + '-' + str(start + cnt - 1) + '页')
# 建立会话
session = requests.Session()
session.encoding = 'utf-8'
headers = {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Connection': 'keep-alive'
}

for page in range(start, start + cnt):
print('开始下载第' + str(page) + '页图片')
# 获得当前页上所有图片的 url
page_url = get_page_url(page)

for i, pic_url in enumerate(page_url, 1):
# 检查文件是否存在,避免重复下载
if os.path.exists(path + pic_url.split('/')[-1] + '.png'):
print('第' + str(page) + '页, 第' + str(i) + '张图片已存在')
continue

try:
r = session.get(pic_url, headers=headers, timeout=5)
soup = BeautifulSoup(r.text, 'lxml')
except:
print('第' + str(page) + '页, 第' + str(i) + '张图片请求失败')
continue

# 解析得到图片原路径以及图片id
img_tag = soup.find('img', id='wallpaper')
img_id = img_tag.get('data-wallpaper-id')
img_raw_url = img_tag.get('src')
# 存储图片名
img_name = path + img_id + '.png'

try:
data = session.get(img_raw_url, headers=headers, timeout=5)
with open(img_name, 'wb') as f:
f.write(data.content)
f.flush()
print('第' + str(page) + '页, 第' + str(i) + '张图片下载成功')
except:
print('第' + str(page) + '页, 第' + str(i) + '张图片下载失败')
else:
time.sleep(1)

print('第' + str(page) + '页图片下载完成')
print('第' + str(start) + '-' + str(start + cnt - 1) + '页图片下载完成')


if __name__ == '__main__':
cur_dir = os.path.dirname(sys.argv[0])
databse_dir = cur_dir + '\\wallhaven_download\\'
if not os.path.exists(databse_dir):
os.makedirs(databse_dir)
download(databse_dir)

结语

对于其他的图片网站,我们也可以采取类似的方法下载图片,当然也可能遇到各种各样的问题,比如图片大小,网站验证等问题,这时候就要具体情况具体分析了吧。

练习之作,如有问题请指出。

相关文章