一个收费图标网站的整站png图标爬取过程记录

一个收费图标网站的整站png图标爬取过程记录

朱治龙
2025-06-11 / 0 评论 / 42 阅读 / 正在检测是否收录...

近期发现一个还不错的3D图标库(https://www.thiings.co/things
mbrc1jao.png

图标偏写实风格,都是png格式,也便于在其他项目中引用,看项目的介绍,有1900个图标,都是偏日常生活物品,可以考虑下载下来,打印给崽做干预训练。

官网提供了下载全部的功能,但下载的时候提示需要29美元,且不支持我仅有的国内的银行卡及在线支付方式,又不得不让我望而却步了。
mbrc9jhm.png

所以不得不祭出国内程序员的大杀器:白嫖。以下便是白嫖全过程。

页面分析

经过对页面源码的分析,发现该网页为使用 Next 开发的单页应用,页面使用 Webpack 打包,滚动页面过程中没有发起异步请求,那相关的文件路径应该是打包在工程里的。

经浏览一个图标,发现如下规律:可通过如下URL下载到原始图片:https://lftz25oez4aqbxpq.public.blob.vercel-storage.com/image-UnbACooeDKA5ggSg36Zi8JizoYINpv.png,经过进一步分析,URL 中的 UnbACooeDKA5ggSg36Zi8JizoYINpv 对应的图片的ID。

经过进一步分析,我们在源码底部找到了相关资源定义的json数据,经过清洗得到如下精简后的json格式的定义数据:

{
  "currentPage": "COLLECTION",
  "shouldShuffle": true,
  "rootPath": "/things",
  "canDownload": true,
  "categories": ["Everyday", "Nature", "Technology", "Sponsors"],
  "forceLength": 1900,
  "items": [
    {
      "id": "amphitheater",
      "name": "Amphitheater",
      "categories": ["places \u0026 structures", "entertainment", "urban"],
      "fileId": "oS7mN2q1OPFw7HHZGO30XoFqCjQJba",
      "shareUrl": "https://www.thiings.co/things/amphitheater"
    },
    {
      "id": "sofa",
      "name": "Sofa",
      "categories": ["everyday life", "furniture", "seating"],
      "fileId": "cRuokpRSq9ekpqqbJA3w5Tg4DWOyLv",
      "shareUrl": "https://www.thiings.co/things/sofa"
    },
    {
      "id": "toaster",
      "name": "Toaster",
      "categories": ["everyday life", "appliance", "kitchen"],
      "fileId": "UnbACooeDKA5ggSg36Zi8JizoYINpv",
      "shareUrl": "https://www.thiings.co/things/toaster"
    },
    {
      "id": "bookshelf",
      "name": "Bookshelf",
      "categories": ["everyday life", "furniture", "storage"],
      "fileId": "4r2tNFAParX1lIOupxBEg3fPYP7GuT",
      "shareUrl": "https://www.thiings.co/things/bookshelf"
    }
  ]
}

由此我们可以遍历json中的items数组获取所有资源,然后拼凑图片URL并逐个下载对应的png原图即可。

资源下载

这种数据爬取方面的操作,还是采用我最熟练的 magic-api 来实现,主要分两个步骤:

1、解析json文件并将文件入库

为了便于后续资源利用,我们将上面的json数据保存到MySQL中,建表语句如下:

-- zzl_resources.things_icons definition

CREATE TABLE `things_icons` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `oid` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '原始id',
  `name` varchar(200) COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
  `categories` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'json数组',
  `categories_str` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '便于按类别搜索的字符串',
  `file_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '文件Id',
  `share_url` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '详情URL',
  `note` varchar(2000) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '详情页的描述信息',
  `add_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='https://www.thiings.co/things 网站的图标爬取专用';

由于json数据较大,我们将数据保存在磁盘文件中(things_resources.json),然后读取解析保存入库,代码如下:

import cn.hutool.core.io.FileUtil
import cn.hutool.core.date.DateTime
import cn.hutool.core.date.DateUtil
import org.jsoup.helper.DataUtil
import cn.hutool.json.JSONUtil
import cn.hutool.core.util.ObjectUtil
import cn.hutool.core.util.StrUtil
import log
var timer = DateUtil.timer();
var jsonStr = FileUtil.readString("/cosmos/apps/uploads/things_resources.json","UTF-8");
var things = JSONUtil.parseArray(jsonStr)
// log.info('jsonStr:' + jsonStr)
for (thingItem in things) {
    var categoriesStr = ''
    if (thingItem.categories && thingItem.categories.length > 0) {
        categoriesStr = "," + thingItem.categories.join(',') + ","
    }
    if (!thingItem.shareUrl) {
        log.info('跳过入库:' + thingItem.fileId)
        continue
    }
    var data = {
        oid: thingItem.id,
        name: thingItem.name,
        categories: JSONUtil.toJsonStr(thingItem.categories),
        categoriesStr: categoriesStr,
        fileId: thingItem.fileId,
        shareUrl: thingItem.shareUrl
    }
    log.info(JSONUtil.toJsonStr(data))
    db['ZR'].table('things_icons').insert(data)
}
log.info(`Cost Time: ${timer.intervalPretty()}.`);
return '操作成功'

2、下载相关的原图

数据保存入库后,我们可以遍历记录,然后下载到指定目录,一下是下载代码:

import cn.hutool.http.HttpUtil
import cn.hutool.core.io.FileUtil
import cn.hutool.core.date.DateTime
import cn.hutool.core.date.DateUtil
import org.jsoup.helper.DataUtil
import cn.hutool.json.JSONUtil
import log
import http
var list = db['ZR'].table('things_icons').select()
var index = 0
var size = list.size()
var timer = DateUtil.timer();
for ( item in list) {
    var fileId = item.fileId
    var url = `https://lftz25oez4aqbxpq.public.blob.vercel-storage.com/image-${fileId}.png`
    try {
        HttpUtil.downloadFileFromUrl(url, `/cosmos/apps/uploads/things-icons/${item.name}__${fileId}.png`)
    } catch(e) {
        log.info(`something error:${item.fileId}`)
    }
    
    index++
    log.info(`index/size:${index}/${size}`) 
    
}
log.info(`Cost Time: ${timer.intervalPretty()}.`);
return 'success'

执行该方法后,耗时 1小时46分。
mbrp4vco.png
下载了 1908 张图片,共计 2.78G
mbsp3nn9.png

通过对下载的图片进行统计,发现所有png图片均为1024*1024的分辨率,每张图片基本上都在1M以上,只要不涉及商用版权纠纷的场景,这样规范的图片可以直接用在很多地方。

0

评论 (0)

取消