本文发自 http://www.binss.me/blog/write-a-spider-in-ten-minutes-to-fetch-the-images/,转载请注明出处。

今晚无聊刷微博,无意中发现一张鹿岛的cos十分传神,经过强大的搜图引擎,获知其在半次元有完整套图。

老司机先开一波车:http://bcy.net/coser/detail/16016/417762

作为一名老司机,对于喜爱的套图,当然是down下来珍藏,然而很显然这种站不会有类似“一键下载”的按钮,于是写个脚本把它搞下来。当然为了一个这么简单的需求,我们当然不能花太多时间去从头到尾搞只爬虫,于是我选择了pyspider。由于先前有学习过这个框架,所以飞速地撸了个脚本把图都抓下来了。

思路

  1. 访问抓取页,如 http://bcy.net/coser/detail/16016/417762

  2. 通过”审查元素“发现,网页上的图片链接,如

    http://img9.bcyimg.com/coser/16016/post/177ne/b43cda60c0c711e5b0892d9b80c834ad.jpg/w650

    是缩放过的,完整图片为

    http://img9.bcyimg.com/coser/16016/post/177ne/b43cda60c0c711e5b0892d9b80c834ad.jpg

    即去掉尾部的w650即可。写个正则进行匹配。

  3. 开启pyspider的css selector helper,在web页面选中图片,得到css选择器 .detail_clickable

    同理得到character和coser的选择器为 .post__role-headline > a.maxw700 > h3 > a

  4. 正则匹配图片url得到原图url和后缀名,拼接character和coser得到文件夹名

  5. 根据文件夹名,如 优歌yuuka - 鹿岛 创建下载文件夹,然后根据url将所有原图下载到该文件夹内

  6. 顺手伪装下headers,比如User-Agent、Referer之类的

完整脚本

# !/usr/bin/env python
# -*- coding: utf-8 -*-
#
# FileName:      bcy.py
# Author:        binss
# Create:        2016-09-03 22:50:32
# Description:   No Description
#

import re
import urllib2
import os
from pyspider.libs.base_handler import *


DOWNLOAD_DIR = '/home/binss/pyspider/download'

fetch_url = 'http://bcy.net/coser/detail/16016/417762'


# e.g. http://img9.bcyimg.com/coser/16016/post/177ne/b43cda60c0c711e5b0892d9b80c834ad.jpg/w650
def download(url, folder, index):
    match = re.search('(.*\.(.*))\/', url)
    if match:
        url = match.group(1)
        print 'downloading {}'.format(url)
        image = urllib2.urlopen(url).read()
        path = os.path.join(DOWNLOAD_DIR, folder)
        if not os.path.exists(path):
            os.makedirs(path)
        filename = os.path.join(path, '{}.{}'.format(index, match.group(2)))
        with open(filename, 'w+') as f:
            f.write(image)


class Handler(BaseHandler):
    crawl_config = {
        'headers': {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
            'Referer': fetch_url,
            'Accept-Language': 'zh-CN,zh;q=0.8',
            'Accept': 'image/webp,image/*,*/*;q=0.8',
            'Accept-Encoding': 'gzip, deflate, sdch',
        }
    }

    def on_start(self):
        self.crawl(fetch_url, callback=self.index_page)

    @config(age=10 * 24 * 60 * 60)
    def index_page(self, response):
        image_urls = []
        character = response.doc('.post__role-headline > a').text()
        coser = response.doc('.maxw700 > h3 > a').text()
        folder = u'{} - {}'.format(coser, character)
        index = 1
        for x in response.doc('.detail_clickable').items():
            image_urls.append(x.attr.src)
            download(x.attr.src, folder, index)
            index += 1

        return {
            'character': character,
            'coser': coser,
            'total': index - 1,
            'debug': image_urls,
        }

流程

  1. 通过 pyspider -c config.json 启动pyspider

  2. 访问webui,由于我通过config.json重定义了端口,所以是 http://127.0.0.1:8888/

  3. 点击Create创建新的Project

  4. http://127.0.0.1:8888/debug/bcy 的代码框中粘入完整脚本

  5. 点击run执行第一步

    然后点击结果中的>后继续点击run

  6. 等待下载完毕,在相应位置得到套图

缺陷

  1. 目测半次元对抓图有流量限制,每次满速抓到一半就没流量了,然后等待几十秒后会继续满速下载。可以考虑代理池

  2. 在run过程中,webui其他页面无法访问(阻塞),目测是urllib2.urlopen(url).read()阻塞了web server。可以考虑异步get。

总结

利用pyspider可以快速开发爬虫,实在是居家必备的利器。作为爬虫爱好者,我裸写过许多爬虫脚本,也开发过简易的爬虫框架,最后发现还是别人的轮子好用。本文仅作抛砖引玉,更多用法请参考文档http://docs.pyspider.org/en/latest/