🎯 Trình duyệt đám mây tùy chỉnh, chống phát hiện được hỗ trợ bởi Chromium tự phát triển, thiết kế dành cho trình thu thập dữ liệu webtác nhân AI. 👉Dùng thử ngay
Quay lại blog

Tải Tệp Puppeteer: Hướng Dẫn Hoàn Chỉnh Cho Các Nhà Phát Triển Node.js

Alex Johnson
Alex Johnson

Senior Web Scraping Engineer

30-Jun-2026

Tóm tắt:

  • Tải xuống trong Chrome không đầu (headless) là một vấn đề của CDP, không phải vấn đề của API Puppeteer. Puppeteer không có page.download() chính thức; bạn điều khiển Giao thức Chrome DevTools trực tiếp với Browser.setDownloadBehavior và lắng nghe Browser.downloadProgress.
  • allowAndName cộng với eventsEnabled là sự kết hợp thực sự báo cáo hoàn thành. Cài đặt hành vi một mình thì chỉ tắt hộp thoại "lưu tệp"; bật sự kiện cho phép bạn await số byte đã hoàn thành thay vì đoán với một khoảng thời gian cố định.
  • Trên một trình duyệt đám mây, tệp sẽ được lưu trên máy chủ — vì vậy bạn lấy lại byte thông qua trang. Một fetch() cùng nguồn gốc bên trong page.evaluate() trả về tệp dưới dạng base64, mà bạn giải mã và ghi vào đĩa cục bộ. Không có máy chủ headful, không có ổ đĩa chia sẻ.
  • Chống bot và bảo vệ theo vùng cũng áp dụng cho tải xuống. Nhiều tệp bị giới hạn chỉ phục vụ cho một IP dân cư ở quốc gia đúng; cố định cổng kết nối với proxyCountry là một phần trong việc đảm bảo tải xuống thành công.
  • Toàn bộ quy trình chạy trên Scrapeless Scraping Browser với một cuộc gọi Puppeteer.connect(). Trình duyệt đám mây tạo phiên, áp dụng việc nhận diện chống lại, và giao cho Puppeteer một điểm cuối WebSocket tiêu chuẩn — mã tải xuống của bạn là CDP bình thường từ đó.
  • Miễn phí để bắt đầu. Các tài khoản Scrapeless mới bao gồm thời gian chạy Scraping Browser miễn phí — đăng ký tại app.scrapeless.com.

Giới thiệu: tại sao "tải xuống một tệp với Puppeteer" khó hơn nó trông

Puppeteer cung cấp cho các nhà phát triển Node.js toàn quyền kiểm soát một trang Chrome — nhấp chuột, gõ, đọc DOM. Tải xuống tệp là một nhiệm vụ phổ biến mà nó không có phương thức chuyên dụng nào. Không có await page.download(selector). Nhấp vào liên kết tải xuống trong một phiên không đầu mặc định thực hiện một trong hai điều không có ích: điều hướng bị chặn, hoặc Chrome chặn chuyển giao vì không có thư mục tải xuống được thiết lập.

Kiểm soát thực sự nằm ở tầng thứ hai, trong Giao thức Chrome DevTools (CDP). Browser.setDownloadBehavior cho Chrome biết tệp sẽ đi đâu và có cho phép hay không; Browser.downloadWillBeginBrowser.downloadProgress báo cáo vòng đời để bạn có thể đợi giây phút chính xác khi một tệp hoàn thành thay vì ngủ và hy vọng.

Chạy điều này trên máy của bạn và bạn vẫn gặp hai vấn đề không liên quan đến CDP: trang đích đánh dấu Chrome không đầu là bot, và các tệp bị giam thường từ chối bất kỳ thứ gì không phải là IP dân cư ở vùng mong đợi. Hướng dẫn này chạy toàn bộ quy trình trên Scrapeless Scraping Browser — một trình duyệt đám mây chống phát hiện, tạo phiên, áp dụng kết nối dân cư, và giao cho Puppeteer một điểm cuối WebSocket bình thường. Mã tải xuống vẫn là CDP thuần khiết; các vấn đề phát hiện và địa lý được xử lý bởi thời gian chạy. Có một điều thú vị mà một trình duyệt đám mây thêm vào — tệp tải xuống ở phía máy chủ — và nửa sau của hướng dẫn này cho thấy cách lấy lại những byte đó về đĩa cục bộ của bạn.


Những gì bạn có thể làm với nó

  • Lấy báo cáo, xuất khẩu, và bảng kê sau khi đăng nhập — PDF hóa đơn, xuất khẩu CSV, tệp phòng dữ liệu — một khi phiên đã được xác thực.
  • Ghi lại các tệp được tạo ra mà một trang xây dựng ở phía client từ một blob (xuất biểu đồ, nút "tải xuống CSV") và không bao giờ tồn tại dưới dạng URL tĩnh.
  • Lấy tài liệu bị gán chỉ phục vụ cho một IP dân cư ở một quốc gia cụ thể, bằng cách cố định cổng kết nối trước khi yêu cầu.
  • Đợi một cách xác định cho một chuyển giao hoàn thành bằng cách sử dụng downloadProgress thay vì một khoảng thời gian cố định dễ bị phá vỡ.
  • Mở rộng cùng một kịch bản trên nhiều tệp hoặc tài khoản mà không cần thiết lập các máy chủ headful — trình duyệt là từ xa.

Tại sao Scrapeless Scraping Browser

Scrapeless Scraping Browser là một trình duyệt đám mây tùy chỉnh, chống phát hiện được thiết kế cho các trình thu thập dữ liệu web và đại lý AI. Đối với các tải xuống Puppeteer cụ thể, nó mang lại:

  • Một kết nối Puppeteer tiêu chuẩnPuppeteer.connect() trả về một đối tượng Browser thông thường, vì vậy mọi cuộc gọi CDP mà bạn đã biết đều hoạt động không thay đổi.
  • Proxy dân cư ở trên 195 quốc gia — cố định proxyCountry để các tệp bị giam phục vụ cho một IP mà chúng tin tưởng.
  • Chống phát hiện ở phía đám mây — phiên trông giống như một trình duyệt thật, vì vậy liên kết tải xuống thực sự được cung cấp thay vì bị ẩn sau một bức tường bot.
  • Kiên trì phiên — giữ cookie và trạng thái xác thực ấm trong suốt quá trình điều hướng, đây là điều làm cho việc tải xuống khi đã đăng nhập trở thành khả thi.
  • Chromium tự phát triển — bề mặt CDP đầy đủ, vì vậy Browser.setDownloadBehavior và các sự kiện tải xuống hoạt động chính xác theo tài liệu.

Nhận khóa API của bạn với gói miễn phí tại app.scrapeless.com.


Điều kiện tiên quyết

  • Node.js 18 hoặc mới hơn
  • Tài khoản Scrapeless và khóa API — đăng ký tại app.scrapeless.com
  • Kiến thức cơ bản về Puppeteer và async/await

Cài đặt

1. Thêm SDK và Puppeteer

SDK Scrapeless tạo phiên làm việc trên đám mây và kết nối Puppeteer với nó. Bạn cần puppeteer-core (khách hàng giao thức không có Chromium đi kèm - trình duyệt ở xa):

bash Copy
npm install @scrapeless-ai/sdk puppeteer-core

2. Đặt khóa API của bạn

Đọc nó từ môi trường; không bao giờ mã cứng:

bash Copy
export SCRAPELESS_API_KEY="your_api_token_here"

Cấu hình: kết nối Puppeteer với trình duyệt đám mây

Puppeteer.connect() tạo ra một phiên Scrapeless và trả về một Browser tiêu chuẩn của Puppeteer. Ghi đè quốc gia proxy ở đây để mọi yêu cầu - bao gồm cả tải xuống - xuất phát từ khu vực bạn muốn:

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

const browser = await Puppeteer.connect({
  apiKey: process.env.SCRAPELESS_API_KEY,
  sessionName: 'puppeteer-downloads',
  proxyCountry: 'US',
  sessionTTL: 300, // giây mà phiên làm việc tồn tại
});

const page = await browser.newPage();

Từ đây, browserpage là các đối tượng tiêu chuẩn của Puppeteer. Mọi thứ dưới đây là CDP tiêu chuẩn.


Triển khai cơ bản: thiết lập hành vi tải xuống và chờ hoàn tất

Có hai cuộc gọi CDP quan trọng và một sự kiện bạn chờ:

  1. Browser.setDownloadBehavior với behavior: 'allowAndName' cho phép tải xuống và đặt tên cho tệp theo GUID ở phía máy chủ. eventsEnabled: true là phần mà hầu hết các hướng dẫn đã bỏ qua - nếu không có nó, sẽ không có sự kiện tiến trình nào được phát và bạn sẽ phải chờ đợi.
  2. Browser.downloadWillBegin cho bạn biết một chuyển giao đã bắt đầu, với suggestedFilenameguid.
  3. Browser.downloadProgress báo cáo inProgresscompleted (hoặc canceled), với receivedBytestotalBytes.
javascript Copy
const cdp = await page.createCDPSession();

await cdp.send('Browser.setDownloadBehavior', {
  behavior: 'allowAndName',
  downloadPath: '/tmp/downloads',
  eventsEnabled: true,
});

// Giải quyết chỉ khi chuyển giao thực sự hoàn tất
const downloadComplete = new Promise((resolve) => {
  let meta = {};
  cdp.on('Browser.downloadWillBegin', (e) => {
    meta = { filename: e.suggestedFilename, guid: e.guid };
  });
  cdp.on('Browser.downloadProgress', (e) => {
    if (e.state === 'completed') {
      resolve({ ...meta, totalBytes: e.totalBytes });
    }
  });
});

Bây giờ, kích hoạt tải xuống - nhấn nút, một liên kết, hoặc như ở đây, một tệp mà trang web tạo ra ở phía khách - và chờ đợi lời hứa:

javascript Copy
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });

// Một nút "tải xuống CSV" tạo tệp trong trình duyệt từ một blob
await page.evaluate(() => {
  const blob = new Blob(['col1,col2\n1,2\n3,4\n'], { type: 'text/csv' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = 'report.csv';
  document.body.appendChild(a);
  a.click();
});

const result = await downloadComplete;
console.log(result);
// { filename: 'report.csv', guid: '845c9455-…', totalBytes: 18 }

Lời hứa giải quyết ngay khi state === 'completed' đến - không có thời gian chờ cố định, và bạn có được số byte thực sự trở lại.

Lấy khóa API của bạn trên gói miễn phí: app.scrapeless.com


Bẻ góc đám mây: lấy byte lên đĩa cục bộ của bạn

Trên một phiên chạy đầu ra địa phương, allowAndName ghi tệp vào downloadPath của bạn và bạn đọc nó từ đĩa. Trên trình duyệt đám mây, tệp nằm trên phiên từ xa, không phải máy của bạn - vì vậy downloadPath là phía máy chủ và /tmp/downloads cục bộ của bạn vẫn trống.

Mô hình đáng tin cậy là lấy byte của tệp bên trong ngữ cảnh trang và trả về chúng dưới dạng base64, sau đó giải mã và ghi cục bộ. Một quy tắc: fetch() tuân theo chính sách cùng nguồn, vì vậy hãy điều hướng đến nguồn của tệp trước, sau đó tải về:

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

const fileUrl = 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf';

// Hạ cánh trên nguồn của tệp để fetch() là cùng nguồn (không bị chặn CORS)
await page.goto(new URL(fileUrl).origin, { waitUntil: 'domcontentloaded' });

const out = await page.evaluate(async (url) => {
  const res = await fetch(url);
  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),
  };
}, fileUrl);

const buffer = Buffer.from(out.b64, 'base64');
writeFileSync('./dummy.pdf', buffer);
console.log({ status: out.status, type: out.type, bytes: buffer.length });
// { status: 200, type: 'application/pdf; qs=0.001', bytes: 13264 }

Bởi vì lệnh fetch chạy bên trong trang đã xác thực, nó mang theo cookies của phiên làm việc — vì vậy các tệp phía sau đăng nhập tải xuống giống như các tệp ở phía trước. Cách tiếp cận sự kiện CDP và cách tiếp cận fetch này bổ sung cho nhau: sử dụng các sự kiện để biết khi nào một lần chuyển đổi kích hoạt bằng click đã hoàn thành; sử dụng fetch trong trang khi bạn đã có URL của tệp và muốn lấy lại dữ liệu cục bộ.


Mô hình nâng cao

Ghim egress cho các tệp bị khóa. Nếu một tài liệu chỉ phục vụ cho một khu vực, hãy đặt proxyCountry tại thời điểm kết nối. Tải xuống sau đó sẽ thừa hưởng IP dân cư đó — không cần thao tác proxy cho mỗi yêu cầu.

Xác thực, rồi tải xuống. Giữ nguyên page (và do đó là phiên làm việc và cookies giống nhau) cho quy trình đăng nhập và tải xuống. Tính năng duy trì phiên không scrap giữ cho trạng thái xác thực ấm áp qua các lần điều hướng, vì vậy việc fetch trên trang sẽ thấy một ngữ cảnh đã đăng nhập.

Đọc tiến trình cho các tệp lớn. Browser.downloadProgress cũng phát ra với state: 'inProgress'receivedBytes đang tăng lên. Ghi lại tỷ lệ so với totalBytes để hiển thị một thanh tiến trình thực thay vì chỉ là một vòng xoay.

Đóng phiên khi hoàn tất. await browser.close() kết thúc phiên làm việc trên cloud một cách nhanh chóng để bạn không giữ runtime mà bạn không sử dụng.


Khắc phục sự cố

Triệu chứng Nguyên nhân Cách khắc phục
Không có sự kiện downloadProgress nào được phát eventsEnabled không được thiết lập Điền eventsEnabled: true vào Browser.setDownloadBehavior
Nhấn vào liên kết chuyển hướng thay vì tải xuống Máy chủ gửi tệp dưới dạng inline, không phải đính kèm Sử dụng mẫu fetch trong trang trên URL tệp
downloadPath cục bộ trống Tệp nằm trên phiên cloud từ xa, không phải trên đĩa của bạn Lấy lại byte qua trang (xem "vòng xoay của cloud")
fetch() ném ra lỗi CORS Xuất xứ trang khác với xuất xứ tệp page.goto(new URL(fileUrl).origin) trước khi fetch
Liên kết tải xuống không bao giờ xuất hiện Trang web ẩn nó phía sau một bức tường bot/geo Ghim proxyCountry và để trình duyệt cloud thực hiện ngón tay để hiển thị trang thực

Kết luận: tải xuống như một bước quan trọng trong quy trình của bạn

Tải xuống tệp bằng Puppeteer bao gồm ba bước: yêu cầu Chrome cho phép và báo cáo tải xuống (Browser.setDownloadBehavior với eventsEnabled), chờ sự kiện hoàn thành thực sự (Browser.downloadProgress), và — trên một trình duyệt cloud — lấy lại byte qua một fetch trong trang với cùng nguồn gốc. Chạy trên Scrapeless Scraping Browser gộp hai phần khó khăn không liên quan đến CDP — phát hiện bot và geo-gating — vào runtime, vì vậy cùng một kịch bản làm việc trên một tệp công khai cũng hoạt động trên một tệp bị khóa, đã đăng nhập. Đối với các quy trình dựa trên biểu mẫu dẫn đến một tệp tải xuống, hãy kết hợp điều này với hướng dẫn trình duyệt cloud Scrapling, và xem trang sản phẩm Scraping Browsertài liệu để biết nền tảng CDP đầy đủ. Ghim egress, giữ phiên làm việc ấm cho các tệp đã xác thực, và chờ completed thay vì ngủ.


Sẵn sàng để xây dựng quy trình dữ liệu AI của bạn?

Tham gia cộng đồng của chúng tôi để nhận kế hoạch miễn phí và kết nối với các nhà phát triển xây dựng quy trình tải xuống và khai thác: Discord · Telegram.

Đăng ký tại app.scrapeless.com để nhận thời gian chạy Scraping Browser miễn phí và điều chỉnh các mẫu trên để phù hợp với các tệp, khu vực và đăng nhập mà quy trình của bạn cần. Xem giá cả để mở rộng quy mô.


Câu hỏi thường gặp

Hỏi: Puppeteer có phương pháp tải xuống tích hợp không?
Không. Không có page.download(). Bạn cấu hình tải xuống thông qua Giao thức Công cụ Phát triển Chrome với Browser.setDownloadBehavior và quan sát chúng với các sự kiện Browser.downloadWillBeginBrowser.downloadProgress.

Hỏi: Tôi có cần proxy để tải xuống tệp không?
Đối với các tệp công khai, không nhất thiết. Đối với các tệp bị khóa theo khu vực hoặc chỉ phục vụ cho các IP dân cư, có — hãy ghim proxyCountry tại thời điểm kết nối để việc chuyển giao diễn ra từ một IP mà trang web tin tưởng.

Hỏi: Tại sao thư mục tải xuống cục bộ của tôi lại trống khi chạy trên một trình duyệt cloud?
Bởi vì tệp tải xuống vào phiên từ xa, không phải máy của bạn. Lấy lại byte bằng cách fetch URL tệp bên trong page.evaluate() và giải mã base64 cục bộ, như đã trình bày ở trên.

Hỏi: Làm thế nào tôi có thể tải xuống một tệp nằm phía sau một đăng nhập?
Xác thực trước trên cùng một trang, sau đó chạy fetch() trong trang - nó mang theo cookie phiên, vì vậy tệp sẽ được tải xuống với tư cách người dùng đã đăng nhập. Tính năng giữ trạng thái phiên không có rác giữ nguyên trạng thái xác thực đó trong suốt các lần điều hướng.

Hỏi: Làm thế nào tôi có thể chờ cho việc tải xuống hoàn tất thay vì đoán một thời gian chờ?
Lắng nghe sự kiện Browser.downloadProgress và giải quyết khi state === 'completed'. Sự kiện này bao gồm receivedBytestotalBytes, vì vậy bạn cũng có thể hiển thị tiến độ thực tế.

Hỏi: Tôi có thể chạy điều này mà không cần một tác nhân AI hoặc công cụ bổ sung không?
Có. Đây là Puppeteer thông thường cộng với CDP trên nền tảng phiên Scrapeless - không cần tác nhân. SDK chỉ tạo ra kết nối.

Tại Scrapless, chúng tôi chỉ truy cập dữ liệu có sẵn công khai trong khi tuân thủ nghiêm ngặt các luật, quy định và chính sách bảo mật trang web hiện hành. Nội dung trong blog này chỉ nhằm mục đích trình diễn và không liên quan đến bất kỳ hoạt động bất hợp pháp hoặc vi phạm nào. Chúng tôi không đảm bảo và từ chối mọi trách nhiệm đối với việc sử dụng thông tin từ blog này hoặc các liên kết của bên thứ ba. Trước khi tham gia vào bất kỳ hoạt động cạo nào, hãy tham khảo ý kiến ​​cố vấn pháp lý của bạn và xem xét các điều khoản dịch vụ của trang web mục tiêu hoặc có được các quyền cần thiết.

Bài viết phổ biến nhất

Danh mục