Python网络爬虫7 - 爬取表情包

为了逗女朋友开心,想找一堆表情包,那么作为一名程序员,自然是会想到用程序来完成这个事情,而Python爬虫就是一个非常好的方法。

我先找到了一个专门发布表情包的网站,就叫做发表情网,可以通过搜索关键词得到大量相关的表情包,下面对这个网站的爬取进行详细介绍。

fabiaoqing

分析站点

为了不引起不适,我选择搜索“你好”,出来的结果是这样的

hello

可以看到共有688个相关的表情,右侧的表情包是分组形式的,不是我的爬取对象。我们只关注表情,在网页底部可以看到分页信息:

page

切换分页到第4页后,可以看到网址的编号情况如下:

hello page 2

网址是https://www.fabiaoqing.com/search/search/keyword/你好/type/bq/page/4.html,据此就可以分析出表情的分页格式

  1. keyword 后接关键词,此处为“你好”
  2. type 后接类型,此处为"bq",对应表情
  3. page 后接页码,此处为"4.html",对应第4页

到此就确定了关键词和分页信息的整合方式,根据这个可以按顺序获取指定关键词的所有分页。那么接下来的问题是如何解析每个分页中的图片信息,下面请看:

hello page 3

每个图片都在一个div标签内,使用chrome的调试工具可以获取到图片元素的xpath路径,然后稍作修改就可以匹配到当前页的所有图片

imgs = page.xpath('//div[@class="searchbqppdiv tagbqppdiv"]//img/@data-original')

好了,到此,网站的分页已经每页的图片获取方式都知道了,下面开始完成代码的编写↓

爬虫的代码实现

  1. 获取指定关键词的所有分页
  2. 从分页中获取所有表情图片的链接
  3. 下载图片并存储到本地

get_imgs

首先对单个关键词,实现分页和图片链接的获取

def get_imgs(keyword):
    '''爬取某一个关键词相关的所有表情包
    Args:
        keyword: 表情包关键词
    '''
    page_index = 0
    img_cnts = 0
    save_dir = get_path(keyword)
    while True:
        page_index = page_index + 1
        # https://fabiaoqing.com/search/search/keyword/抱抱/type/bq/page/1.html
        url = '{}{}/type/bq/page/{}.html'.format(base_url, keyword, page_index)
        response = requests.get(url, headers=headers).content
        page = html.fromstring(response)
        imgs = page.xpath(
            '//div[@class="searchbqppdiv tagbqppdiv"]//img/@data-original')

        print('爬取 "{}" 相关表情包第 {} 页:'.format(keyword, page_index))
        img_cnts = download_imgs(imgs, img_cnts, save_dir)

        if page_index == 1:
            page_num = int(
                page.xpath('//*[@id="mobilepage"]/text()')[0].split()[-1])

        if page_index == page_num:
            break

    return img_cnts, save_dir

思路很简单,就是从1不断增加分页页码page_index,然后使用lxml中的xpath解析网页得到图片链接,最后使用下面介绍的download_imgs函数下载图片。那么什么时候停止获取呢?就是比较首页获取的总分页数page_num和当前分页数page_index是否一致,如果一致说明已经到最后一页。

函数中的get_path是个获取本地存储链接的函数,base_urlheaders是两个全局变量

base_url = 'https://fabiaoqing.com/search/search/keyword/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36'
}


def get_path(keyword):
    '''生成指定关键词对应的表情包存储路径'''
    home_path = os.path.expanduser('~')
    path = os.path.join(home_path, 'Pictures/python/表情包/' + keyword)
    if not os.path.isdir(path):
        os.makedirs(path)

    return os.path.realpath(path)

download_imgs

def download_imgs(img_urls, starti, save_dir):
    '''下载单个页面内所有图片
    Args:
        img_urls: 关键词相关表情包某一分页的所有图片链接
        starti: 当前页面首个图片命名id
        save_dir: 图片存储路径
    '''
    fid = starti
    for img in img_urls:
        print('\t' + img)
        fid = fid + 1
        file_name = '{}.{}'.format(fid, os.path.basename(img).split('.')[-1])
        save_path = os.path.join(save_dir, file_name)

        try:
            with open(save_path, 'wb') as f:
                f.write(requests.get(img, headers=headers, timeout=20).content)
        except requests.exceptions.ConnectionError as ce:
            print(ce.strerror())
        except requests.exceptions.MissingSchema:
            print(img + ' missing schema')
        except requests.exceptions.ReadTimeout:
            print('get {} timeout, skip this item.'.format(img))
        finally:
            pass

    return fid

别看代码这么长,下载图片的关键就两行,和以往下载图片的方式大同小异,不再赘述。

with open(save_path, 'wb') as f:
    f.write(requests.get(img, headers=headers, timeout=20).content)

main

主函数也比较简单,从命令行参数中获取所有关键词,逐个对关键词进行对应的表情爬取并统计爬取到的表情数。

def main():
    if len(sys.argv) < 2:
        usage()
        sys.exit(0)

    print('============================================')
    for keyword in sys.argv[1:]:
        print('开始爬取关键词为 "{}" 的表情包:'.format(keyword))
        count, save_dir = get_imgs(keyword)
        print('共爬取 "{}" 表情包 {} 个'.format(keyword, count))
        print('文件存储于"{}"'.format(save_dir))
    print('\n爬取完成!')
    print('============================================')

由于我们的目的是根据输入的关键词参数获取相关的表情,代码完成后的使用方式是这样的:

python fabiaoqing_spider.py keyword1 keyword2 ...

所以usage函数是这样的,可以同时爬取多个关键词

def usage():
    print('Usage:\n\t' + os.path.basename(sys.argv[0]) +
          ' [key1] [key2] [key3] ...\n')

爬取测试

python fabiaoqing_spider.py 你好 抱抱 亲亲

test1

test2

test3

上面是截取的部分爬取过程,下面是亲亲表情包的爬取结果

test4

代码已托管至Github capturer项目,欢迎交流。

好啦,最后祝大家撩妹成功!