手把手教你爬取斗图啦表情包

爬取表情包

闲来无事,突然想到表情包好久没有更新了,正好这几天学了爬虫,利用爬虫来更新一波表情包,哈哈哈。

有一个网站,叫做“斗图啦”,网址是:https://www.doutula.com/。这里面包含了许许多多的有意思的斗图图片,还蛮好玩的。这里我分析了两种方式获取斗图啦的表情包:

1.利用 Scrapy 框架爬取斗图啦最新套图

2.通过斗图啦网站提供的 API 接口,获取 json 获取图片(异步IO)

说明:本爬虫纯粹是个人娱乐,如果他人使用该爬虫对网站服务器造成不良影响与本人无关。

Scrapy框架爬取套图

页面分析

页面分析是为了找到这些图片或者 URL 之间的规律,通过这些规律我们在写爬虫去获取相应的内容,如图:

页面分析

通过上图,我们可以发现 “ http://www.doutula.com/article/list/?page=2 ” 中 page 参数表示当前是第几页。套图详情是在 “ http://www.doutula.com/article/detail/xxxxx ” 这个地址下面的,其中 xxxxx 是一个类似套图id的一串数字(因为后面我们是用正则来匹配这串数字,所以具体是多少不重要啦~)。我们要找的表情包就在详情页面下,接着分析详情页面,如图:

套图详情分析图

由此我们可以发现套图里面的表情包是放在详情页面下有 “class=pic-content” 的 div 标签下的一组 class 属性为 artile_des 的 div 标签里面的,只是它嵌套的比较深是在每个 div 标签下的table>tbody>tr>td>a下。

编写Spider

通过上面的分析我们知道,只需要爬取 “http://www.doutula.com/article/detail/xxxxxx” 和 “ http://www.doutula.com/article/list/?page=x ”这两类页面就可以了。

框架结构:

爬虫目录结构

爬虫--bqbspider.py:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.spider import CrawlSpider, Rule
from scrapy.linkextractor import LinkExtractor

from bqb.items import BqbItem


class BqbspiderSpider(CrawlSpider):
    name = 'bqbspider'
    allowed_domains = ['www.doutula.com']
    start_urls = ['http://www.doutula.com/article/list/']
    rules = (
        Rule(LinkExtractor(allow=(r'http://www.doutula.com/article/list/\?page=\d+'))),
        Rule(LinkExtractor(allow=(r'http://www.doutula.com/article/detail/\d+')), callback='get_image_parse'),
    )

    def get_image_parse(self, response):
        item = BqbItem()
        item['title'] = response.xpath('//div[@class="pic-title"]/h1/a/text()').extract_first()
        item['data'] = {}
        pic_list = response.xpath('//div[@class="pic-content"]//div[@class="artile_des"]')
        for pic in pic_list:
            pic_url = pic.xpath('./table/tbody/tr[1]/td/a/img/@src').extract_first()
            pic_name = pic.xpath('./table/tbody/tr[1]/td/a/img/@alt').extract_first()
            item['data'][pic_name] = pic_url
        return item

注意:Rule 中定义的规则,会从当前 url 请求的 response 中去进行匹配,如果当前规则匹配成功,并且指定了 callback 回调函数,那么就会请求该 url 并执行回调函数, 如果没有指定回调函数,则表示爬虫继续跟进匹配到的 url。

items.py 文件中定义爬虫返回的字段:

import scrapy

class BqbItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    data = scrapy.Field()

pipelines.py文件中定义了对爬虫爬取到的内容进行的处理操作:

import os
import requests


class BqbPipeline(object):

    def process_item(self, item, spider):
        dir_name = dict(item)['title']
        if not os.path.exists("E:\\images\\" + dir_name):
            os.mkdir("E:\\images\\" + dir_name)
        data = dict(item)['data']
        for pic in data:
            pic_url = data[pic]
            print(pic_url.rfind('/'))
            name = pic_url[pic_url.rfind('/') + 1:]
            filename = "E:\\images\\" + dir_name + "\\" + name
            try:
                with open(filename, 'wb') as f:
                    f.write(requests.get(data[pic]).content)
            except IOError as e:
                print(e)
            print(name, '下载完成!')

这里爬虫的主要代码就没有了,剩下的就是根据自己的需要配置settings.py文件了,建议设置cookie,和缓存,并配置适当的请求数和延迟。

部分爬取效果截图:

爬取结果图一

REST接口获取图片

REST接口就简单多了,这是网址提供的请求接口,这就只需要我们构造一个url请求,获取到服务器返回的 json 即可。在返回的 json 中就有表情包的下载链接,直接下载就可以了。啥都不说了,直接上代码:

import re

import requests
import asyncio

# 批量生成 url 请求参数列表
def create_json(key, mine=0):
    params = []
    for i in range(1, 51):
        data = {
            'type': 'photo',
            'more': 1,
            'keyword': key,
            'page': i,
            'mime': mine,
        }
        params.append(data)
    return params

# 下载并保持图片
@asyncio.coroutine
def save_pic(url):
    if re.search(r'^/[a-z].*', url):
        url = 'https://www.doutula.com' + url
    if url.startswith('//'):
        url = 'https:' + url
    if re.search(r'jpg|gif|png', url):
        b_img = requests.get(url, headers=headers).content
        filename = './images/' + url[url.rfind('/') + 1:]
        try:
            with open(filename, 'wb') as f:
                f.write(b_img)
        except IOError as e:
            print(e)
        finally:
            pass

# 获取图片url列表
@asyncio.coroutine
def download_img(param):
    url = 'https://www.doutula.com/api/search'
    img_list = requests.get(url, params=param, headers=headers).json()['data']['list']
    while len(img_list) > 0:
        img = img_list.pop()
        yield from save_pic(img['image_url'])
        print('%s下载完成' % img['out_id'])


headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' \
                  ' (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'
}


def main():
    loop = asyncio.get_event_loop()
    params = create_json('蘑菇头')
    tasks = [download_img(param) for param in params]
    loop.run_until_complete(asyncio.wait(tasks))
    print('Complete!')


if __name__ == '__main__':
    main()

获取结果图:

REST效果图

你可能感兴趣的:(手把手教你爬取斗图啦表情包)