Bing 首页图片合集抓取

By BenHeart

微软 Bing 首页以每日更新高质量壁纸而闻名,很多人喜欢下载作为桌面壁纸,本文介绍一种抓取 Bing 首页图片合集的思路。

抓取来源

分析思路

由于本文需要抓取所有 Bing 首页图片的合集,所以选择 http://www.bing.com/gallery/(已失效) 作为抓取来源。 用 Chrome 浏览器打开该网址,页面布局如图: 身为程序员,习惯性 F12 检查下页面元素,我发现所有图片都在 id="gird" 的 div 块中,页面结构如图: 按下 Ctrl + Shift + C 点击列表中一张图片,HTML 代码如图: 点击图片查看详情,按下 Ctrl + Shift + C 点击大图,HTML 代码如图: 由此大胆猜测,图片 url 结构为: http(s)://az619519.vo.msecnd.net/files/{img_name}_{resolution}.jpg
只要获得 {img_name} 就可以抓取对应的图片了。

打开 Network -> Doc 菜单,最开始 id="gird" 的 div 块并没有数据,说明是通过 js 请求数据并渲染出来的: 打开 Network -> JS 菜单,果然看到我想要的数据: 数据是在 js 代码中,可以通过正则表达式提取出来,再转成 json 格式,数据结构如下:

{
    "imageIds": ["31781", "31771", "31761", ...],
    "categories": ["Nature", "Nature", "Animal", ...],
    "tags": ["Beach", "Plant / tree", "Mammal", ...],
    "holidays": ["", "", "Father's Day", ...],
    "regions": ["South America,", "", "", ...],
    "countries": ["Peru", "", "", ...],
    "colors": ["Multi", "Multi", "Brown", ...],
    "shortNames": ["PlayaRoja", "AeoniumLeaf", "TurDad", ...],
    "imageNames": ["PlayaRoja_EN-US9542724846", "AeoniumLeaf_EN-US7200082197", "TurDad_EN-US11284438848", ...],
    "dates": [20170620, 20170619, 20170618, ...]
}

imageNames 正好对应图片 url 中的 {img_name}。至此,就可以很轻松构造图片的 url。

以第一张图为例,根据猜测的图片 url 构成规则,对应的图片 url 为:
http(s)://az619519.vo.msecnd.net/files/PlayaRoja_EN-US9542724846_1366x768.jpg
打开链接,就是第一张分辨率为 1366x768 的图片,说明刚才猜测的图片 url 构成规则是正确的。

Python 代码

  • bing_gallery_crawler.py
# -*- coding: utf-8 -*-
import json
import re
import requests
import shutil

data_url = 'http://www.bing.com/gallery/home/browsedata?z=0'
# img_detail_base_url = 'http://www.bing.com/gallery/home/imagedetails/%s?z=0'
regex = r'a\.browseData=(.+);}\)\(window, \'BingGallery\'\);'
img_base_url = 'https://az619519.vo.msecnd.net/files/%s_%s.jpg'
resolution = '1366x768'

gallery_data_js = requests.get(data_url)
gallery_data_match = re.search(regex, gallery_data_js.content)
if gallery_data_match:
    gallery_data_json = json.loads(gallery_data_match.group(1))
    img_ids = gallery_data_json['imageIds']
    img_names = gallery_data_json['imageNames']
    short_names = gallery_data_json['shortNames']
    for index in xrange(len(img_ids)):
        # img_detail_url = img_detail_base_url % img_ids[index]
        img_url = img_base_url % (img_names[index], resolution)
        file_name = short_names[index] + '.jpg'
        img_stream = requests.get(img_url, stream=True)
        if img_stream.status_code == 200:
            with open(file_name, 'wb') as fw:
                shutil.copyfileobj(img_stream.raw, fw)
else:
    print "No match!"

参考链接

about theme

BenHeart

A graduate from HIT, attention to the Network Programming, Website Development, Data Mining.

GitHub Repository