Tối ưu hóa lưu lượng trình duyệt không đầu: Chiến lược giảm chi phí với Puppeteer cho việc thu thập dữ liệu hiệu quả

Senior Web Scraping Engineer
Tổng quan
Khi sử dụng Puppeteer để thu thập dữ liệu, mức tiêu thụ lưu lượng là một yếu tố quan trọng cần xem xét. Đặc biệt khi sử dụng dịch vụ proxy, chi phí lưu lượng có thể tăng đáng kể. Để tối ưu hóa mức sử dụng lưu lượng, chúng ta có thể áp dụng các chiến lược sau:
- Chặn tài nguyên: Giảm mức tiêu thụ lưu lượng bằng cách chặn các yêu cầu tài nguyên không cần thiết.
- Chặn URL yêu cầu: Giảm lưu lượng hơn nữa bằng cách chặn các yêu cầu cụ thể dựa trên đặc điểm URL.
- Mô phỏng thiết bị di động: Sử dụng cấu hình thiết bị di động để nhận các phiên bản trang nhẹ hơn.
- Tối ưu hóa tổng thể: Kết hợp các phương pháp trên để đạt được kết quả tốt nhất.
Kế hoạch tối ưu hóa 1: Chặn tài nguyên
Giới thiệu về Chặn tài nguyên
Trong Puppeteer, page.setRequestInterception(true)
có thể chặn mọi yêu cầu mạng được khởi xướng bởi trình duyệt và quyết định tiếp tục (request.continue()
), dừng lại (request.abort()
), hoặc tùy chỉnh phản hồi (request.respond()
).
Phương pháp này có thể giảm đáng kể mức tiêu thụ băng thông, đặc biệt phù hợp cho các tình huống thu thập dữ liệu, chụp ảnh màn hình, và tối ưu hóa hiệu suất.
Các loại tài nguyên có thể chặn và gợi ý
Loại tài nguyên | Mô tả | Ví dụ | Tác động sau khi chặn | Khuyến nghị |
---|---|---|---|---|
image |
Tài nguyên hình ảnh | Hình JPG/PNG/GIF/WebP | Hình ảnh sẽ không được hiển thị | ⭐ An toàn |
font |
Tập tin phông chữ | Phông TTF/WOFF/WOFF2 | Phông chữ mặc định của hệ thống sẽ được sử dụng thay thế | ⭐ An toàn |
media |
Tập tin media | Tập tin video/audio | Nội dung media không thể phát | ⭐ An toàn |
manifest |
Manifest ứng dụng web | Tập tin cấu hình PWA | Chức năng PWA có thể bị ảnh hưởng | ⭐ An toàn |
prefetch |
Tài nguyên prefetch | <link rel="prefetch"> |
Tác động tối thiểu đến trang | ⭐ An toàn |
stylesheet |
Tập tin CSS | Tập tin CSS bên ngoài | Kiểu trang bị mất, có thể ảnh hưởng đến bố cục | ⚠️ Cẩn thận |
websocket |
WebSocket | Kết nối truyền thông thời gian thực | Chức năng thời gian thực bị vô hiệu hóa | ⚠️ Cẩn thận |
eventsource |
Sự kiện từ máy chủ | Dữ liệu push từ máy chủ | Chức năng push bị vô hiệu hóa | ⚠️ Cẩn thận |
preflight |
Yêu cầu preflight CORS | Yêu cầu OPTIONS | Các yêu cầu khác nguồn thất bại | ⚠️ Cẩn thận |
script |
Tập tin JavaScript | Tập tin JS bên ngoài | Chức năng động bị vô hiệu hóa, SPA có thể không được hiển thị | ❌ Tránh |
xhr |
Yêu cầu XHR | Yêu cầu dữ liệu AJAX | Không thể lấy dữ liệu động | ❌ Tránh |
fetch |
Yêu cầu Fetch | Yêu cầu AJAX hiện đại | Không thể lấy dữ liệu động | ❌ Tránh |
document |
Tài liệu chính | Trang HTML chính | Trang không thể tải | ❌ Tránh |
Giải thích Mức độ Khuyến nghị:
- ⭐ An toàn: Việc chặn hầu như không ảnh hưởng đến việc thu thập dữ liệu hoặc hiển thị màn hình đầu tiên; được khuyến nghị chặn theo mặc định.
- ⚠️ Cẩn thận: Có thể làm gãy kiểu dáng, các chức năng thời gian thực, hoặc các yêu cầu khác nguồn; cần đánh giá từ thực tế.
- ❌ Tránh: Có khả năng cao gây ra sự cố cho các trang SPA/dynamic không thể hiển thị hoặc lấy dữ liệu một cách bình thường, trừ khi bạn hoàn toàn chắc chắn rằng bạn không cần những tài nguyên này.
Ví dụ mã chặn tài nguyên
javascript
import puppeteer from 'puppeteer-core';
const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';
async function scrapeWithResourceBlocking(url) {
const browser = await puppeteer.connect({
browserWSEndpoint: scrapelessUrl,
defaultViewport: null
});
const page = await browser.newPage();
// Bật chặn yêu cầu
await page.setRequestInterception(true);
// Định nghĩa các loại tài nguyên để chặn
const BLOCKED_TYPES = new Set([
'image',
'font',
'media',
'stylesheet',
]);
// Chặn yêu cầu
page.on('request', (request) => {
if (BLOCKED_TYPES.has(request.resourceType())) {
request.abort();
console.log(`Đã chặn: ${request.resourceType()} - ${request.url().substring(0, 50)}...`);
} else {
request.continue();
}
});
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Trích xuất dữ liệu
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000)
};
});
await browser.close();
return data;
}
// Sử dụng
scrapeWithResourceBlocking('https://www.scrapeless.com')
javascript
.then(data => console.log('Kết quả thu thập dữ liệu:', data))
.catch(error => console.error('Thu thập dữ liệu không thành công:', error));
Lược đồ Tối ưu hóa 2: Chặn URL yêu cầu
Ngoài việc chặn theo loại tài nguyên, có thể thực hiện kiểm soát chặn chi tiết hơn dựa trên đặc điểm URL. Điều này đặc biệt hiệu quả để chặn quảng cáo, script phân tích và các yêu cầu bên thứ ba không cần thiết khác.
Chiến lược Chặn URL
- Chặn theo miền: Chặn tất cả các yêu cầu từ một miền cụ thể
- Chặn theo đường dẫn: Chặn các yêu cầu từ một đường dẫn cụ thể
- Chặn theo loại tệp: Chặn các tệp với phần mở rộng cụ thể
- Chặn theo từ khóa: Chặn các yêu cầu mà URL chứa từ khóa cụ thể
Các mẫu URL có thể chặn thường gặp
Mẫu URL | Mô tả | Ví dụ | Khuyến nghị |
---|---|---|---|
Dịch vụ quảng cáo | Miền mạng quảng cáo | ad.doubleclick.net , googleadservices.com |
⭐ An toàn |
Dịch vụ phân tích | Các script thống kê và phân tích | google-analytics.com , hotjar.com |
⭐ An toàn |
Plugin mạng xã hội | Nút chia sẻ xã hội, v.v. | platform.twitter.com , connect.facebook.net |
⭐ An toàn |
Điểm theo dõi | Điểm theo dõi hành vi người dùng | URL chứa pixel , beacon , tracker |
⭐ An toàn |
Tệp phương tiện lớn | Tệp video, âm thanh lớn | Các phần mở rộng như .mp4 , .webm , .mp3 |
⭐ An toàn |
Dịch vụ phông chữ | Dịch vụ phông chữ trực tuyến | fonts.googleapis.com , use.typekit.net |
⭐ An toàn |
Tài nguyên CDN | Tài nguyên tĩnh CDN | cdn.jsdelivr.net , unpkg.com |
⚠️ Cảnh báo |
Mã Ví dụ Chặn URL
javascript
import puppeteer from 'puppeteer-core';
const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';
async function scrapeWithUrlBlocking(url) {
const browser = await puppeteer.connect({
browserWSEndpoint: scrapelessUrl,
defaultViewport: null
});
const page = await browser.newPage();
// Bật chặn yêu cầu
await page.setRequestInterception(true);
// Định nghĩa các miền và mẫu URL cần chặn
const BLOCKED_DOMAINS = [
'google-analytics.com',
'googletagmanager.com',
'doubleclick.net',
'facebook.net',
'twitter.com',
'linkedin.com',
'adservice.google.com',
];
const BLOCKED_PATHS = [
'/ads/',
'/analytics/',
'/pixel/',
'/tracking/',
'/stats/',
];
// Chặn các yêu cầu
page.on('request', (request) => {
const url = request.url();
// Kiểm tra miền
if (BLOCKED_DOMAINS.some(domain => url.includes(domain))) {
request.abort();
console.log(`Chặn miền: ${url.substring(0, 50)}...`);
return;
}
// Kiểm tra đường dẫn
if (BLOCKED_PATHS.some(path => url.includes(path))) {
request.abort();
console.log(`Chặn đường dẫn: ${url.substring(0, 50)}...`);
return;
}
// Cho phép các yêu cầu khác
request.continue();
});
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Trích xuất dữ liệu
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000)
};
});
await browser.close();
return data;
}
// Sử dụng
scrapeWithUrlBlocking('https://www.scrapeless.com')
.then(data => console.log('Kết quả thu thập dữ liệu:', data))
.catch(error => console.error('Thu thập dữ liệu không thành công:', error));
Lược đồ Tối ưu hóa 3: Mô phỏng Thiết bị Di động
Mô phỏng thiết bị di động là một chiến lược tối ưu hóa lưu lượng hiệu quả khác vì các trang web di động thường cung cấp nội dung trang nhẹ hơn.
Lợi ích của Mô phỏng Thiết bị Di động
- Phiên bản trang nhẹ hơn: Nhiều trang web cung cấp nội dung cô đọng hơn cho thiết bị di động
- Tài nguyên hình ảnh nhỏ hơn: Phiên bản di động thường tải hình ảnh nhỏ hơn
- CSS và JavaScript đơn giản hóa: Phiên bản di động thường sử dụng kiểu dáng và script đơn giản hóa
- Giảm quảng cáo và nội dung không cốt lõi: Phiên bản di động thường loại bỏ một số chức năng không cốt lõi
- Phản hồi thích ứng: Nhận được bố trí nội dung tối ưu cho màn hình nhỏ
Cấu hình Mô phỏng Thiết bị Di động
Dưới đây là các tham số cấu hình cho một số thiết bị di động được sử dụng phổ biến:
javascript
const iPhoneX = {
viewport: {
width: 375,
height: 812,
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
isLandscape: false
}
};
Hoặc sử dụng trực tiếp các phương pháp tích hợp của puppeteer để mô phỏng thiết bị di động
javascript
import { KnownDevices } from 'puppeteer-core';
const iPhone = KnownDevices['iPhone 15 Pro'];
const trình duyệt = await puppeteer.launch();
const trang = await trình duyệt.newPage();
await trang.emulate(iPhone);
javascript
const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';
async function optimizedScraping(url) {
console.log(`Bắt đầu quét tối ưu: ${url}`);
// Ghi lại lưu lượng sử dụng
let totalBytesUsed = 0;
const browser = await puppeteer.connect({
browserWSEndpoint: scrapelessUrl,
defaultViewport: null
});
const page = await browser.newPage();
// Thiết lập chặn yêu cầu
await page.setRequestInterception(true);
// Chặn các yêu cầu
page.on('request', (request) => {
request.continue();
});
// Giám sát lưu lượng mạng
page.on('response', async (response) => {
const headers = response.headers();
const contentLength = headers['content-length'] ? parseInt(headers['content-length'], 10) : 0;
totalBytesUsed += contentLength;
});
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Giả lập cuộn trang để kích hoạt nội dung tải chậm
await page.evaluate(() => {
window.scrollBy(0, window.innerHeight);
});
await new Promise(resolve => setTimeout(resolve, 1000));
// Trích xuất dữ liệu
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000),
links: Array.from(document.querySelectorAll('a')).slice(0, 10).map(a => ({
text: a.innerText,
href: a.href
}))
};
});
// Xuất thông tin thống kê lưu lượng sử dụng
console.log(`\nThống kê Lưu lượng Sử dụng:`);
console.log(`Đã sử dụng: ${(totalBytesUsed / 1024 / 1024).toFixed(2)} MB`);
await browser.close();
return data;
}
// Sử dụng
optimizedScraping('https://www.scrapeless.com')
.then(data => console.log('Quét hoàn tất:', data))
.catch(error => console.error('Quét không thành công:', error));
Sau khi chạy mã không tối ưu, chúng ta có thể thấy sự khác biệt về lưu lượng rất rõ ràng từ thông tin được in ra:
Tình huống | Lưu lượng Sử dụng (MB) | Tỷ lệ Tiết kiệm |
---|---|---|
Không tối ưu | 6.03 | — |
Tối ưu | 0.81 | ≈ 86.6 % |
Bằng cách kết hợp các phương pháp tối ưu hóa trên, việc tiêu thụ lưu lượng proxy có thể giảm đáng kể, hiệu quả quét có thể được cải thiện, và đảm bảo rằng nội dung cốt lõi cần thiết được thu thập.
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.