🎯 一款可定制、具备反检测功能的云浏览器,由自主研发的 Chromium驱动,专为网页爬虫AI 代理设计。👉立即试用
返回博客

图像爬虫:如何批量抓取网站上的图像

Isabella Garcia
Isabella Garcia

Web Data Collection Specialist

30-Jun-2026

TL;DR:

  • src 属性是寻找图像的最低可靠性来源。 现代页面将真实 URL 放在 srcsetdata-src 中,或者仅在懒加载触发后设置 — 读取 currentSrc 和数据属性,而不仅仅是 src
  • 懒加载的图像在你滚动到它们之前并不存在。 首先自动滚动页面,以便加载器将占位符替换为真实 URL,然后进行收集。
  • 将每个 URL 解析为绝对路径并保留元数据。 new URL(src, location.href) 修复相对和协议相对路径;altnaturalWidthnaturalHeight 也应与 URL 一起记录。
  • 通过页面下载,而不是简单的 HTTP 客户端。 在渲染会话中的同源 fetch() 会携带 CDN 期望的 cookies 和引用来源,因此热链接保护的图像会返回,而不是 403。
  • 它在真实浏览器上运行,这就是重点。 Scrapeless Scraping Browser 渲染构建画廊的 JavaScript,并提供居民出口,因此图像以访问者的方式加载。
  • 免费开始。 新注册的 Scrapeless 账户包括免费的 Scraping Browser 运行时 — 访问 app.scrapeless.com 注册。

引言:为什么“只抓取 img 标签”不起作用

抓取图像听起来像是一行代码 — 选择每个 <img>,读取 src,完成。在真实网站上,这个方法立即失效。画廊会懒加载,因此大多数图像在 src 中有占位符,真实 URL 在 data-src 中,直到你将它们滚动到视图中。响应式图像srcset 中提供多个候选项,浏览器在运行时选择其中一个。URL 可能是相对的或协议相关的。当你确实拥有 URL 时,CDN 通常会拒绝一个普通的 HTTP 下载,因为它期望实际页面视图的 cookies 和引用来源

因此,一个可靠的图像抓取器实际上有四个步骤:在真实浏览器中渲染页面,滚动以强制懒加载图像加载,读取解析的图像 URL(不是原始属性)加上其元数据,通过渲染会话下载字节。

本指南在 Scrapeless Scraping Browser上运行这四个步骤 — 一个连接到 Puppeteer 的反检测云浏览器 — 以下每段代码都是在一个实际的图像繁多的页面上运行的。仅限公共图像。


你可以用它做什么

  • 批量收集页面上的每个图像,包括解析后的 URL、替代文本和尺寸。
  • 处理懒加载和无限滚动的画廊,通过在收集之前滚动来实现。
  • 提取响应式图像,通过读取 currentSrc(浏览器实际选择的候选项)。
  • 批量下载,通过页面下载以便热链接保护的 CDN 提供文件。
  • 按大小过滤,使用自然尺寸跳过图标、间隔和跟踪像素。

为什么选择 Scrapeless Scraping Browser

Scrapeless Scraping Browser 是一个可定制的反检测云浏览器,专为网络爬虫和 AI 代理设计。针对图像抓取,它带来了:

  • 自家开发的 Chromium — 渲染构建画廊的 JS,触发懒加载器,因此真实的 URL 显示出来。
  • 反检测指纹识别 — 会话表现得像真实浏览器,因此图像繁多页面及其 CDN 正常提供服务。
  • 覆盖195多个国家的住宅代理 — 从页面和其图像 CDN 信任的 IP 进行出口。
  • 会话持久性 — 保持 cookies 活跃,以便页面内下载带上正确的凭证。
  • 标准 Puppeteer 连接Puppeteer.connect() 返回一个普通的 Browser;你的收集代码是纯 Puppeteer。

获得免费的计划中的 API 密钥,请访问 app.scrapeless.com


先决条件

  • Node.js 18 或更高版本
  • 一个 Scrapeless 账户和 API 密钥 — 请在 app.scrapeless.com 注册
  • 基本的 Puppeteer 使用熟悉度

安装

bash Copy
npm install @scrapeless-ai/sdk puppeteer-core
bash Copy
export SCRAPELESS_API_KEY="your_api_token_here"

第一步 — 连接并加载页面

javascript Copy
import { Puppeteer } from '@scrapeless-ai/sdk';

const browser = await Puppeteer.connect({
  apiKey: process.env.SCRAPELESS_API_KEY,
  sessionName: 'image-scraper',
  proxyCountry: 'US',
  sessionTTL: 300,
});

const page = await browser.newPage();
await page.goto('https://books.toscrape.com/', {
  waitUntil: 'networkidle2',
  timeout: 60000,
});

networkidle2 等待直到初始图像请求完成,因此折叠图像已经在 DOM 中。


第二步 — 滚动以触发懒加载图像

折叠图像通常保持为占位符,直到它们滚动到视图中。按照步骤向下滚动页面,暂停以便加载器能够插入真实 URL:

javascript Copy
await page.evaluate(async () => {
  for (let y = 0; y < document.body.scrollHeight; y += 600) {
    window.scrollBy(0, 600);
等待新的 Promise((r) => setTimeout(r, 300));  
}  
});  

对于无限滚动画廊,循环这个直到 document.body.scrollHeight 不再增长 —— 这表示没有更多的图像可加载。

在免费计划中获取您的 API 密钥: app.scrapeless.com


步骤 3 — 收集解析后的 URL 和元数据

读取浏览器实际解析的 URL,回退到常见的懒加载属性,并使每个 URL 变为绝对地址:

javascript Copy
const images = await page.evaluate(() => {
  const abs = (u) => { try { return new URL(u, location.href).href; } catch { return null; } };
  return [...document.querySelectorAll('img')]
    .map((img) => {
      const src =
        img.currentSrc ||           // 浏览器选择的候选项(处理 srcset)
        img.src ||
        img.getAttribute('data-src') ||
        img.getAttribute('data-lazy-src');
      return {
        src: abs(src),
        alt: img.alt || null,
        width: img.naturalWidth,
        height: img.naturalHeight,
      };
    })
    .filter((i) => i.src);
});

console.log(images.length, 'images');
console.log(images[0]);
// 20 images
// {
//   src: 'https://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg',
//   alt: 'A Light in the Attic',
//   width: 125,
//   height: 155
// }

currentSrc 是关键:对于响应式 srcset 图像,它提供了浏览器在当前视口中选择的候选项,而不是猜测。捕获 naturalWidth/naturalHeight 允许您在稍后使用简单的大小过滤器删除图标和空白。


步骤 4 — 通过页面下载图像

通过裸 HTTP 客户端下载时,热链接保护就会造成问题 — CDN 无法看到引荐来源或 Cookies,因此返回 403。而是在页面上下文中获取每个图像,以便它带有会话凭据,并在本地解码 base64:

javascript Copy
import { writeFileSync } from 'node:fs';

const url = images[0].src;
const out = await page.evaluate(async (u) => {
  const res = await fetch(u);
  const bytes = new Uint8Array(await res.arrayBuffer());
  let binary = '';
  for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
  return { status: res.status, type: res.headers.get('content-type'), b64: btoa(binary) };
}, url);

writeFileSync('./image-0.jpg', Buffer.from(out.b64, 'base64'));
console.log({ status: out.status, type: out.type, bytes: Buffer.from(out.b64, 'base64').length });
// { status: 200, type: 'image/jpeg', bytes: 9876 }

对收集到的 images 进行循环以批量下载,保持请求之间的小延迟和适度的并发,以使 CDN 保持愉快。


您获得的回馈

每个收集的图像都是一个扁平记录 — 解析的 URL 加上元数据:

json Copy
[
  {
    "src": "https://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg",
    "alt": "A Light in the Attic",
    "width": 125,
    "height": 155
  }
]
// 来自 books.toscrape.com 的真实捕获(首页上有 20 张图片)。值会随着页面的变化而变化。

一些诚实的观察:

  • 微小的尺寸通常不是内容。 过滤掉低于某个阈值(比如 50×50)以去掉图标、图块和跟踪像素。
  • srcset 意味着存在多个分辨率。 currentSrc 提供视口适当的图像;如果您特别想要最大的,则解析原始 srcset
  • 背景图像不是 <img> 标签。 CSS background-image URL 存在于计算样式中 — 如果画廊使用它们,单独收集这些。
  • 通过页面下载 适用于检查引荐来源的任何 CDN;裸请求会返回 403。

结论:一个可靠的批量图像抓取器

一个可靠的图像抓取器是渲染 → 滚动 → 读取解析后的 URL → 通过页面下载。跳过滚动将错过懒加载图像;读取原始 src 而不是 currentSrc 将获得占位符;用裸客户端下载时,热链接保护的 CDN 将拒绝您。在 Scrapeless Scraping Browser 上运行提供了真正的浏览器和住宅出口,使画廊能够正常加载。要收集页面 URL 而不是图像,请参见 Etsy 抓取器指南Scraping Browser 产品页面文档 涵盖了完整的 SDK 接口。先滚动,读取 currentSrc,保持元数据,并通过会话获取字节。


准备构建您的 AI 驱动的数据管道了吗?

加入我们的社区以索取免费计划,并与正在构建图像和媒体管道的开发者联系:Discord · Telegram

app.scrapeless.com 注册以获得免费的 Scraping Browser 运行时,并将上述模式适应您的工作流程所需的画廊和 CDN。查看 定价 了解规模。


常见问题

问:从网站抓取图像合法吗?
收集公开可见的图像通常是被允许的,但版权和网站的服务条款仍适用于您使用它们的方式。仅抓取公共图像,尊重许可证,查看服务条款,并咨询律师以了解您的用例。

问:为什么我的抓取的 src 值是空白或很小的占位符?
因为图像是延迟加载的。先滚动页面,以便加载器将占位符替换为真实的 URL,并读取 currentSrc/data-src 而不仅仅是 src

问:我该如何处理无限滚动的画廊?
循环执行滚动步骤,直到 document.body.scrollHeight 停止增加,然后收集 — 这表示没有更多图像将加载。

问:我的下载返回 403,尽管 URL 在浏览器中有效,为什么?
CDN 正在检查引用者/ cookies(热链接保护)。使用页面内的 fetch() 下载,以便请求携带已渲染会话的凭证。

问:我如何获得最高分辨率的版本?
解析原始的 srcset 并选择最大的候选项,而不是反映当前视口的 currentSrc

问:我需要代理吗?
对于公共图像页面,通常不需要 — 但是固定 proxyCountry 会提供一个一致的住宅 IP,图像密集型页面及其 CDN 将其视为正常访问者。

问:我可以在没有 AI 代理的情况下运行这个吗?
可以。这只是对 ScrapeLess 会话的普通 Puppeteer — 不需要代理。

在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。

最受欢迎的文章

目录