[P1] Tìm hiểu Headless browser & Puppeteer

Dạo gần đây mình có mày mò cách lấy dữ liệu từ các trang báo: 24h, dantri ... Qua đó mình cũng biết thêm được những khái niệm mới (đối với mình): Headless browser, Puppeteer. Vậy chúng là cái gì & sử dụng ra sao

1. Headless browser là gì

Headless Browser là một trình duyệt web không có giao diện đồ họa người dùng. Các headless browser cung cấp tương tác tự động một trang web trong một môi trường giống như các trình duyệt web phổ biến khác, nhưng nó được thực hiện thông qua giao diện dòng lệnh hoặc qua một mạng truyền thông. Chúng đặc biệt hữu ích cho việc kiểm thử các trang web vì chúng có thể hiển thị và hiểu HTML giống như các trình duyệt thông thường, bao gồm các cả styling như bố cục trang, màu sắc, font chữ và thực thi Javascript và AJAX mà thường không có sẵn khi sử dụng các phương pháp kiểm thử khác.

1.1: Trường hợp sử dụng

  • Kiểm tra tự động hóa trong các ứng dụng web hiện đại.
  • Chụp ảnh màn hình của các trang web.
  • Chạy các bài kiểm tra tự động cho các thư viện JavaScript.
  • Scrape các trang web cho dữ liệu.
  • Tự động tương tác của các trang web.

2. Puppeteer là gì

Puppeteer là một bộ thư viện của Nodejs, giúp bạn điều khiển headless Chrome. Những gì mà bạn làm được bằng giao diện người dùng trên Chrome thì bạn đều có thể làm bằng Puppeteer

  • Chụp màn hình và lưu lại thành file ảnh hoặc PDF
  • Lấy dữ liệu từ website cho dù site đó bắt ta phải login hay dùng AJAX để load data
  • Tự động submit form, UI testing, keyboard input ...
  • Tạo ra môi trường automated testing. Chạy trực tiếp test của bạn trên phiên bản Chrome mới nhất
  • Chụp lại timeline trace site của bạn để giúp cho việc chẩn đoán những vấn đề về hiện năng

2.1: Cài đặt

yarn add puppeteer
# or "npm i puppeteer"

Lưu ý: Khi bạn cài đặt Puppeteer, nó sẽ download về phiên bản chromium mới nhất (~71Mb Mac, ~90Mb Linux, ~110Mb Win)

Puppeteer yêu cầu Nodejs v6.4.0 trở lên. Nhưng code mình chủ yếu dùng async/await nên Nodejs của bạn cần phải từ v7.6.0 trở lên. Như mình thì mình xài v9.4.2

2.2: Chụp màn hình

Ta sẽ di chuyển đến trang 24h.com.vn và chụp lại ảnh mnaf hình rồi lưu lại với tên 24h.png

// file 24h.js
const puppeteer = require('puppeteer');

(async () => {
// mở trình duyệt
  const browser = await puppeteer.launch({ headless: false });
  // Mở 1 page mới
  const page = await browser.newPage();
  // đi đến trang 24h
  await page.goto('https://24h.com.vn');
  // chụp ảnh màn hình và lưu lại với tên 24h.png
  await page.screenshot({path: '24h.png'});
  // Lưu ảnh màn hình thành file pdf
  await page.pdf({path: 'hn.pdf', format: 'A4'});

// tắt trình duyệt
  await browser.close();
})();

Run command node 24h.js & đây là kết quả Trình duyệt mới sẽ được bật lên. Bạn để í thì đây không phải là chrome nhé mà chính là Chromium lúc nãy ta download về Để ẩn trình duyệt này thì ta bỏ tham số { headless: false } Còn nếu bạn muốn bật trình duyệt lên để debug hoặc xem cho vui thì ta có thể set kích thước cho nó bằng cách

page.setViewport({width: 1280, height: 720});

2.3: Chạy js trong browser

Nếu chỉ có mỗi chụp màn hình thì chắc hẳn puppeteer này cũng không có gì đặc sắc. evaluate là hàm quan trọng nhất của thằng này

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://24h.com.vn');

  // Get the "viewport" of the page, as reported by the page.
  const dimensions = await page.evaluate(() => {
    return {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight,
      deviceScaleFactor: window.devicePixelRatio
    };
  });
  console.log('Dimensions:', dimensions);
  await browser.close();
})();

Ở ví dụ trên ta lấy kích thước của website, mình có thể dùng js thuần để lấy dữ liệu của page đó & trả về qua return rồi lưu vào db

3. Thủ thuật debug

  1. Tắt chế độ headless - chế độ này rất hữu dụng, ta có thể nhìn xem browser hiển thị & hoạt động có đúng í muốn của ta không. Thay vì chỉ debug trên console, ta có thể xem toàn bộ browser bằng cách sử dụng headless: false
const browser = await puppeteer.launch({headless: false});
  1. Giảm tốc độ - slowMo cho phép giảm tốc độ của Puppeteer xuống bằng cách chỉ định số mili giây. Đây là một cách khác giúp ta xem chuyện gì sẽ xảy ra với code của chúng ta
 const browser = await puppeteer.launch({
   headless: false,
   slowMo: 250 // slow down by 250ms
 });
  1. Chụp lại console - Bạn có thể lắng nghe sự kiện console. Thử chạy đoạn code sau xem sao nhé
 page.on('console', msg => console.log('PAGE LOG:', msg.text()));
 await page.evaluate(() => console.log(`url is ${location.href}`));
  1. Bật chế độ verbose logging - Tất cả các API công khai & nội bộ được gọi thì sẽ đều được ghi log thông qua chế độ debug với namespace là puppeteer
 # Basic verbose logging
 env DEBUG="puppeteer:*" node script.js

 # Debug output can be enabled/disabled by namespace
 env DEBUG="puppeteer:*,-puppeteer:protocol" node script.js # everything BUT protocol messages
 env DEBUG="puppeteer:session" node script.js # protocol session messages (protocol messages to targets)
 env DEBUG="puppeteer:mouse,puppeteer:keyboard" node script.js # only Mouse and Keyboard API calls

 # Protocol traffic can be rather noisy. This example filters out all Network domain messages
 env DEBUG="puppeteer:*" env DEBUG_COLORS=true node script.js 2>&1 | grep -v '"Network'

3. Kết luận

Vậy là mình đã giới thiệu qua khái niệm & một vài kiến thức cơ bản về thằng puppeteer rồi Ở phần sau mình sẽ dùng thằng này để lấy ảnh/dữ liệu từ 1 trang web thực tế nhé

Tài liệu tham khảo

https://github.com/GoogleChrome/puppeteer https://puppetron.now.sh/ https://try-puppeteer.appspot.com/ https://www.google.com.vn/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&cad=rja&uact=8&ved=0ahUKEwjwsZ7z3PDYAhXMj5QKHSNRCCoQFghPMAU&url=https%3A%2F%2Fdevelopers.google.com%2Fweb%2Ftools%2Fpuppeteer%2F&usg=AOvVaw0rJATETQwoWYIKhQzPIcM0