全程干货,用 python 下载某站全部免抠图片,图片背景透明,格式PNG

Posted 梦想橡皮擦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全程干货,用 python 下载某站全部免抠图片,图片背景透明,格式PNG相关的知识,希望对你有一定的参考价值。

作为一个素材收集狂,遇到一个好的图片站,那是必须要盘它的。这次就碰到一个 PNG images 号称有 100000+ 免费的 PNG 图片。

免抠图片站点分析

目标站点:http://pngimg.com/
目标数据:全站 PNG 图片,一键下载。
该网站具备非常多的分类页,在采集过程中,优先采集该分类页数据。

分类页地址通过开发者工具查看,得到如下内容

该地址需要与域名信息进行拼接,得到详情页地址,例如 anaconda 地址如下:

http://pngimg.com/images/animals/anaconda

打开详情页,检查图片所在区域,目的获取图片地址,测试过程中发现图片列表页并未分页,即一页即可获取全部数据。

基于上述内容,整理逻辑如下:

  1. 获取所有图片分类标签;
  2. 基于分类进入图片列表页;
  3. 提取图片列表页图片地址;
  4. 下载图片

编码时间

由于本案例涉及文件的读写操作,所以采用多线程实现,代码分为 3 个部分,采集分类,采集图片地址,下载图片。

采集分类代码如下

import random
import logging
import threading
from typing import Optional, Text
import requests
from bs4 import BeautifulSoup
import lxml

logging.basicConfig(level=logging.NOTSET)
thread_lock = threading.Lock()

def get_headers():
    uas = [
        "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)",
        "Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)",
    ]
    ua = random.choice(uas)
    headers = {
        "user-agent": ua
    }
    return headers


# 通用的 requests get 请求方法
def get_html(url: Text, headers: dict, timeout: int) -> Optional[Text]:
    try:
        res = requests.get(url=url, headers=headers, timeout=timeout)
    except Exception as e:
        logging.error(e)

    if res is not None:
        return res.text
    else:
        return None


if __name__ == '__main__':
    url = "http://pngimg.com/"
    headers = get_headers()
    # 获取首页的 HTML 数据
    html_str = get_html(url, headers, 5)
    # 解析首页的HTML数据,获取所有列表页链接
    soup = BeautifulSoup(html_str, 'lxml')

    div_parents = soup.find_all(attrs={'class': 'sub_category'})

    # 获取到所有的详情页地址
    all_links = []
    for div in div_parents:
        all_links.extend(div.find_all('a'))

    print("累计获取到", len(all_links), "个列表页数据")

上述代码中将 get_headers() 函数单独提炼,后续将函数直接作为参数,传递到对应类的构造方法中即可。

提取到所有的分类标签存储到 all_links 变量中,后续由于多线程需要共享全局变量,顾提前导入线程锁:

thread_lock = threading.Lock()

PNG 采集与下载类

class PngImg(threading.Thread):
    # 构造函数
    def __init__(self, thread_name, headers_func, requests_func) -> None:
        threading.Thread.__init__(self)
        self._headers = headers_func()
        self._timeout = 5
        self.requests_func = requests_func
        self._thread_name = thread_name

    def run(self) -> None:
        bast_host = "http://pngimg.com"
        while True:

            thread_lock.acquire() # 全局锁,获取地址
            global all_links
            if all_links is None:
                break

            list_url = bast_host + all_links.pop().get('href')
            thread_lock.release()
            print(self._thread_name + " 正在运行,采集的地址是 " + list_url)

            list_html_str = self.requests_func(url=list_url, headers=self._headers, timeout=self._timeout)
            ret_imgs = self._get_imgs(list_html_str)

            self._save(ret_imgs)

    def _get_imgs(self, html) -> list:
        """获取所有的图片地址
        :return: 图片 list
        """
        soup = BeautifulSoup(html, 'lxml')
        # 获取图片所在 div 标签
        div_imgs = soup.find_all(attrs={'class': 'png_imgs'})
        # 图片地址为空,用来保存图片 tag

        imgs_src = []
        for div_img in div_imgs:
            # 遍历 div 标签,检索后代标签中的 img 图片标签
            imgs_src.append(div_img.a.img.get("src"))

        return imgs_src

    def _save(self, imgs):
        """保存图片 """
        for img in imgs:
            img = img.replace('small/', '')  # 去除 small 标记,获取大图
            img_url = "https://pngimg.com{}".format(img)  # 拼接完整图片访问地址
            name = img[img.rfind('/') + 1:]
            # print(img_url)
            # print(name)

            try:
                res = requests.get(url=img_url, headers=self._headers, timeout=self._timeout)
            except Exception as e:
                logging.error(e)

            if res is not None:
                name = name.replace("/", "_")
                with open(f'./imgs/{self._thread_name}_{name}', "wb+") as f:
                    f.write(res.content)

代码说明:
上述类为核心采集类,重写了 run 方法,在其中通过循环实现对所有列表页的采集,_get_imgs() 方法用于获取所有图片地址,用到的依旧是 BeautifulSoup 对象的 find_all() 方法,标签检索使用子集标签寻找方式 div_img.a.img.get("src")_save() 方法用于存储图片,在这里橡皮擦第一次测试的时候,发现图片路径中带有 small 关键字,如希望获取大图,需要对其进行删除,后续测试发现已经移除该标记。

类的构造方法参数说明如下:

def __init__(self, thread_name, headers_func, requests_func) -> None:
  • thread_name:线程名;
  • headers_funcget_headers() 函数;
  • requests_func:请求函数;

线程的开启代码直接写在 main 代码块中即可,本案例使用 5 个线程。

    threads = ["Thread A", "Thread B", "Thread C", "Thread D", "Thread E"]
    for t in threads:
        my_thread = PngImg(t, get_headers, get_html)
        my_thread.start()

代码运行过程效果图如下所示:

获取图片也是非常快速的。

写在后面

BeautifulSoup 模块的学习暂时告一段落,希望这3篇文章,能让你对 bs4 模块有一个初步的认识。

今天是持续写作的第 240 / 365 天。
期待 关注点赞评论收藏

更多精彩

《爬虫 100 例,专栏销售中,买完就能学会系列专栏》

以上是关于全程干货,用 python 下载某站全部免抠图片,图片背景透明,格式PNG的主要内容,如果未能解决你的问题,请参考以下文章

python 趣味案例,通过模糊文件名,获取某站资源榜真实下载地址

Python爬虫技术干货,教你如何实现抓取京东店铺信息及下载图片

干货台大李宏毅两个小时带你纵览自然语言处理和语音内容机器理解,附全程视频PPT下载

我入侵了隔壁妹子的Wifi,发现。。。(全程实战干货,建议收藏)

我入侵了隔壁妹子的Wifi,发现。。。(全程实战干货,建议收藏)

硬核!OpenCV机器学习深度学习实战教程分享(全程干货)