专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
码农翻身  ·  中国的大模型怎么突然间就领先了? ·  17 小时前  
程序员的那些事  ·  清华大学:DeepSeek + ... ·  3 天前  
程序员小灰  ·  3个令人惊艳的DeepSeek项目,诞生了! ·  2 天前  
OSC开源社区  ·  2024: 大模型背景下知识图谱的理性回归 ·  4 天前  
程序员的那些事  ·  成人玩偶 + ... ·  5 天前  
51好读  ›  专栏  ›  SegmentFault思否

70 行 Python 代码实现壁纸批量下载

SegmentFault思否  · 公众号  · 程序员  · 2018-02-03 08:00

正文

项目地址:https://github.com/jrainlau/wallpaper-downloader

前言

好久没有写文章了,因为最近都在适应新的岗位,以及利用闲暇时间学习python。这篇文章是最近的一个python学习阶段性总结,开发了一个爬虫批量下载某壁纸网站的高清壁纸。

注意:本文所属项目仅用于python学习,严禁作为其他用途使用!

初始化项目

项目使用了 virtualenv 来创建一个虚拟环境,避免污染全局。使用 pip3 直接下载即可:

  1. pip3 install virtualenv

然后在合适的地方新建一个 wallpaper-downloader 目录,使用 virtualenv 创建名为 venv 的虚拟环境:

  1. virtualenv venv

  2. . venv/bin/activate

接下来创建依赖目录:

  1. echo bs4 lxml requests > requirements.txt

最后yun下载安装依赖即可:

  1. pip3 install -r requirements.txt

分析爬虫工作步骤

为了简单起见,我们直接进入分类为“aero”的壁纸列表页:http://wallpaperswide.com/aero-desktop-wallpapers.html/page/1。

可以看到,这一页里面一共有10张可供下载的壁纸。但是由于这里显示的都是缩略图,作为壁纸来说清晰度是远远不够的,所以我们需要进入壁纸详情页,去找到高清的下载链接。从第一张壁纸点进去,可以看到一个新的页面:

因为我机器是Retina屏幕,所以我打算直接下载体积最大的那个以保证高清(红圈所示体积)。

了解了具体的步骤以后,就是通过开发者工具找到对应的dom节点,提取相应的url即可,这个过程就不再展开了,读者自行尝试即可,下面进入编码部分。

访问页面

新建一个 download.py 文件,然后引入两个库:

  1. from bs4 import BeautifulSoup

  2. import requests

接下来,编写一个专门用于访问url,然后返回页面html的函数:

  1. def visit_page(url):

  2.    headers = {

  3.      'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36'

  4.    }

  5.    r = requests.get(url, headers = headers)

  6.    r.encoding = 'utf-8'

  7.    return BeautifulSoup(r.text, 'lxml')

为了防止被网站反爬机制击中,所以我们需要通过在header添加UA把爬虫伪装成正常的浏览器,然后指定utf-8编码,最后返回字符串格式的html。

提取链接

在获取了页面的html以后,就需要提取这个页面壁纸列表所对应的url了:

  1. def get_paper_link(page):

  2.    links = page.select('#content > div > ul > li > div > div a')

  3.    return [link.get('href') for link in links]

这个函数会把列表页所有壁纸详情的url给提取出来。

下载壁纸

有了详情页的地址以后,我们就可以进去挑选合适的size了。在对页面的dom结构分析后可以知道,每一个size都对应着一个链接:

所以第一步,就是把这些size对应的链接提取出来:

  1. wallpaper_source = visit_page(link)

  2. wallpaper_size_links = wallpaper_source.select('#wallpaper-resolutions > a')

  3. size_list = [{

  4.    'size': eval(link.get_text().replace('x', '*')),

  5.    'name': link.get('href').replace('/download/', ''),

  6.    'url': link.get('href' )

  7. } for link in wallpaper_size_links]

size_list 就是这些链接的一个集合。为了方便接下来选出最高清(体积最大)的壁纸,在 size 中我使用了 eval 方法,直接把这里的 5120x3200 给计算出来,作为 size 的值。

获取了所有的集合之后,就可以使用 max() 方法选出最高清的一项出来了:

  1. biggest_one = max(size_list, key = lambda item: item['size'])

这个 biggest_one 当中的 url 就是对应size的下载链接,接下来只需要通过 requests 库把链接的资源下载下来即可:

  1. result = requests.get(PAGE_DOMAIN + biggest_one['url'])

  2. if result.status_code == 200:

  3.    open('wallpapers/' + biggest_one['name'], 'wb').write(result.content)

注意,首先你需要在根目录下创建一个 wallpapers 目录,否则运行时会报错。

整理一下,完整的 download_wallpaper 函数长这样:

  1. def download_wallpaper(link):

  2.    wallpaper_source = visit_page(PAGE_DOMAIN + link)

  3.    wallpaper_size_links = wallpaper_source.select('#wallpaper-resolutions > a')

  4.    size_list = [{

  5.         'size': eval(link.get_text().replace('x', '*')),

  6.        'name': link.get('href').replace('/download/', ''),

  7.        'url': link.get('href')

  8.    } for link in wallpaper_size_links]

  9.    biggest_one = max(size_list, key = lambda item: item['size'])

  10.    print('Downloading the ' + str(index + 1) + '/' + str(total) + ' wallpaper: ' + biggest_one['name'])

  11.    result = requests.get(PAGE_DOMAIN + biggest_one['url'])

  12.    if result.status_code == 200:

  13.        open('wallpapers/' + biggest_one['name'], 'wb').write(result.content)

批量运行

上述的步骤仅仅能够下载 第一个壁纸列表页 第一张壁纸 。如果我们想下载 多个列表页 全部壁纸 ,我们就需要循环调用这些方法。首先我们定义几个常量:

  1. import sys

  2. if len(sys.argv) != 4:

  3.    print('3 arguments were required but only find ' + str(len(sys.argv) - 1) + '!')

  4.    exit()

  5. category = sys.argv[1]

  6. try:

  7.    page_start = [int(sys.argv[2])]

  8.    page_end = int(sys.argv[3])

  9. except:

  10.    print('The second and third arguments must be a number but not a string!')

  11.    exit()

这里通过获取命令行参数,指定了三个常量 category , page_start page_end ,分别对应着壁纸分类,起始页页码,终止页页码。

为了方便起见,再定义两个url相关的常量:

  1. PAGE_DOMAIN = 'http://wallpaperswide.com'

  2. PAGE_URL = 'http://wallpaperswide.com/' + category + '-desktop-wallpapers/page/'

接下来就可以愉快地进行批量操作了,在此之前我们来定义一个 start() 启动函数:

  1. def start():

  2.    if page_start[0] <= page_end:

  3.        print('Preparing to download the ' + str(page_start[0])  + ' page of all the "' + category + '" wallpapers...')

  4.        PAGE_SOURCE = visit_page(PAGE_URL + str(page_start[0]))

  5.        WALLPAPER_LINKS = get_paper_link(PAGE_SOURCE)

  6.        page_start[0] = page_start[0] + 1

  7.        for index, link in enumerate(WALLPAPER_LINKS):







请到「今天看啥」查看全文