Giới thiệu về Puppeteer

Giới thiệu về cách điều khiển Chrome theo chương trình từ Node.js

Puppeteer là một thư viện Node mà chúng ta có thể sử dụng để điều khiểnChrome không đầuví dụ. Về cơ bản, chúng tôi đang sử dụng Chrome, nhưng sử dụng JavaScript theo chương trình.

Sử dụng nó, chúng ta có thể:

  • cạo các trang web
  • tự động hóa việc gửi biểu mẫu
  • thực hiện bất kỳ loại tự động hóa trình duyệt nào
  • theo dõi hiệu suất tải trang
  • tạo các phiên bản được hiển thị phía máy chủ của các ứng dụng trang đơn
  • tạo ảnh chụp màn hình
  • tạo thử nghiệm tự động hóa
  • tạo PDF từ các trang web

Nó được xây dựng bởi Google. Nó không mở khóa bất cứ điều gì mới, nhưng nó tóm tắt nhiều chi tiết thực tế mà chúng tôi sẽ phải xử lý, nếu không sử dụng nó.

Trong ngắn hạn, nó làm cho mọi thứ rất dễ dàng.

Vì nó quay một phiên bản Chrome mới khi nó được khởi chạy, nó có thể không phải là phiên bản hoạt động tốt nhất. Đó là cách chính xác nhất để tự động hóa thử nghiệm với Chrome, vì Chrome đang sử dụngtrình duyệt thực tếdưới mui xe.

Nói một cách chính xác, nó sử dụng Chromium phần nguồn mở của Chrome, điều này chủ yếu có nghĩa là bạn không có codec độc quyền được Google cấp phép và không thể mở nguồn (MP3, AAC, H.264 ..) và bạn không được tích hợp với các dịch vụ của Google như báo cáo sự cố, cập nhật của Google và hơn thế nữa, nhưng theo quan điểm có lập trình, tất cả đều phải giống 100% với Chrome (như đã lưu ý).

Cài đặt Puppeteer

Bắt đầu bằng cách cài đặt nó bằng

npm install puppeteer

trong dự án của bạn.

Thao tác này sẽ tải xuống và gói phiên bản Chromium mới nhất.

Bạn có thể chọn làm cho puppeteer chạy cài đặt cục bộ của Chrome mà bạn đã cài đặt bằng cách cài đặtpuppeteer-corethay vào đó, điều này hữu ích trong một số trường hợp đặc biệt (xemngười múa rối vs người múa rối). Thông thường, bạn chỉ đi vớipuppeteer.

Sử dụng Puppeteer

Trong tệp Node.js, hãy yêu cầu nó:

const puppeteer = require('puppeteer');

sau đó chúng ta có thể sử dụnglaunch()phương pháp để tạo một phiên bản trình duyệt:

(async () => {
  const browser = await puppeteer.launch()
})()

Chúng ta cũng có thể viết như thế này:

puppeteer.launch().then(async browser => {
  //...
})

Bạn có thể chuyển một đối tượng với các tùy chọn đếnpuppeteer.launch(). Phổ biến nhất là

puppeteer.launch({ headless:false })

để hiển thị Chrome trong khi Puppeteer đang thực hiện các hoạt động của nó. Thật tuyệt khi xem những gì đang xảy ra và gỡ lỗi.

Chúng tôi sử dụngawaitvà vì vậy chúng ta phải gói lời gọi phương thức này trong mộtchức năng không đồng bộ, mà chúng tôingay lập tức gọi.

Tiếp theo, chúng ta có thể sử dụngnewPage()phương pháp trênbrowserđối tượng để có đượcpagevật:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
})()

Tiếp theo, chúng tôi gọigoto()phương pháp trênpageđối tượng để tải trang đó:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://website.com')
})()

Chúng tôi cũng có thể sử dụng các lời hứa, thay vì async / await, nhưng sử dụng phần sau làm cho mọi thứ dễ đọc hơn nhiều:

(() => {
  puppeteer.launch().then(browser => {
    browser.newPage().then(page => {
      page.goto('https://website.com').then(() => {
        //...
      })
    })
  })
})()

Lấy nội dung trang

Khi chúng tôi có một trang được tải bằng URL, chúng tôi có thể lấy trang đóNội dunggọi choevaluate()phương pháp củapage:

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://website.com')
<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">result</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">page</span>.<span style="color:#a6e22e">evaluate</span>(() =&gt; {
<span style="color:#75715e">//...

}) })()

Phương thức này sử dụng một hàm gọi lại, nơi chúng ta có thể thêm mã cần thiết để truy xuất các phần tử của trang mà chúng ta cần. Chúng tôi trả về một đối tượng mới và đây sẽ là kết quả củaevaluate()cuộc gọi phương thức.

Chúng ta có thể sử dụngpage.$()phương pháp để truy cậpAPI bộ chọnphương phápquerySelector()trên tài liệu, vàpage.$()như một bí danh choquerySelectorAll().

Khi chúng tôi hoàn thành các tính toán của mình, chúng tôi gọiclose()phương pháp trênbrowser:

browser.close()

Phương pháp trang

Chúng tôi đã thấy ở trênpageđối tượng mà chúng tôi nhận được từ cuộc gọibrowser.newPage()và chúng tôi gọi làgoto()evaluate()các phương pháp trên đó.

Tất cả các phương thức đều trả về một lời hứa, vì vậy chúng thường được thêm vào trướcawaittừ khóa.

Hãy xem nàomột sốtrong số các phương pháp phổ biến nhất mà chúng tôi sẽ gọi.Bạn có thể xem danh sách đầy đủ trên tài liệu về Puppeteer.

page.$()

Cấp quyền truy cập vàoAPI bộ chọnphương phápquerySelector()trên trang

page.$()

Cấp quyền truy cập vàoAPI bộ chọnphương phápquerySelectorAll()trên trang

page.$eval()

Chấp nhận 2 hoặc nhiều tham số. Đầu tiên là một bộ chọn, thứ hai là một chức năng. Nếu có nhiều tham số hơn, những tham số đó sẽ được truyền dưới dạng đối số bổ sung cho hàm.

Nó chạyquerySelectorAll()trên trang, sử dụng tham số đầu tiên làm bộ chọn, sau đó nó sử dụng tham số đó làm đối số đầu tiên cho hàm.

const innerTextOfButton = await page.$eval('button#submit', el => el.innerText)

click()

Thực hiện sự kiện nhấp chuột vào phần tử được truyền dưới dạng tham số

await page.click('button#submit')

Chúng ta có thể chuyển một đối số bổ sung với một đối tượng tùy chọn:

  • buttoncó thể được đặt thànhleft(mặc định),righthoặc làmiddle
  • clickCountlà một số mặc định là 1 và đặt số lần phần tử sẽ được nhấp vào
  • delaylà số mili giây giữa các lần nhấp. Mặc định là0

content()

Lấy nguồn HTML của một trang

const source = await page.content()

emulate()

Mô phỏng một thiết bị. Nó đặt tác nhân người dùng thành một thiết bị cụ thể và đặt chế độ xem cho phù hợp.

Danh sách các thiết bị được hỗ trợ có sẵntrong tập tin này.

Đây là cách bạn mô phỏng iPhone X:

iPhone X

const puppeteer = require('puppeteer');
const device = require('puppeteer/DeviceDescriptors')['iPhone X'];

puppeteer.launch().then(async browser => { const page = await browser.newPage() await page.emulate(device)

//do stuff await browser.close() })

evaluate()

Đánh giá một chức năng trong ngữ cảnh trang. Bên trong chức năng này, chúng tôi có quyền truy cập vàodocumentđối tượng, vì vậy chúng tôi có thể gọi bất kỳ API DOM:

const puppeteer = require('puppeteer');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

const result = await page.evaluate(() => { return document.querySelectorAll(’.footer-tags a’).length })

console.log(result) })()

Mọi thứ chúng ta gọi ở đây đều được thực thi trong ngữ cảnh trang, vì vậy nếu chúng ta chạyconsole.log(), chúng tôi sẽ không thấy kết quả trong ngữ cảnh Node.js vì nó được thực thi trong trình duyệt không có đầu.

Chúng tôi có thể tính toán các giá trị ở đây và trả về một đối tượng JavaScript, nhưng nếu chúng tôi muốn trả về một phần tử DOM và truy cập nó trong ngữ cảnh Node.js, chúng tôi phải sử dụng một phương pháp khác,evaluateHandle(). Nếu chúng tôi trả về một phần tử DOM từ eval (), chúng tôi sẽ chỉ nhận được một đối tượng trống.

evaluateHandle()

Tương tự như eval (), nhưng nếu chúng tôi trả về một phần tử DOM, chúng tôi sẽ lấy lại đối tượng thích hợp chứ không phải là một đối tượng trống:

const puppeteer = require('puppeteer');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

const result = await page.evaluateHandle(() => { return document.querySelectorAll(’.footer-tags a’) })

console.log(result) })()

exposeFunction()

Phương pháp này cho phép bạn thêm một hàm mới trong ngữ cảnh trình duyệt, hàm này được thực thi trong ngữ cảnh Node.js.

Điều này có nghĩa là chúng ta có thể thêm một hàm chạy mã Node.js bên trong trình duyệt.

Ví dụ này thêm một hàm test () bên trong ngữ cảnh trình duyệt đọc tệp “app.js” từ hệ thống tệp, với đường dẫn liên quan đến tập lệnh:

const puppeteer = require('puppeteer');
const fs = require('fs');

(async () => { const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto(https://flaviocopes.com)

await page.exposeFunction(‘test’, () => { const loadData = (path) => { try { return fs.readFileSync(path, ‘utf8’) } catch (err) { console.error(err) return false } } return loadData(‘app.js’) })

const result = await page.evaluate(() => { return test() })

console.log(result) })()

focus()

Tập trung vào bộ chọn được truyền dưới dạng tham số

await page.focus('input#name')

goBack()

Quay lại lịch sử điều hướng trang

await page.goBack()

goForward()

Chuyển tiếp trong lịch sử điều hướng trang

await page.goForward()

goto()

Mở một trang mới.

await page.goto('https://flaviocopes.com')

Bạn có thể truyền một đối tượng dưới dạng tham số thứ hai, với các tùy chọn. CácwaitUntiltùy chọn, nếu vượt quanetworkidle2giá trị sẽ đợi cho đến khi điều hướng hoàn tất:

await page.goto('https://flaviocopes.com', {waitUntil: 'networkidle2'})

hover()

Thực hiện di chuột qua bộ chọn được truyền dưới dạng tham số

await page.hover('input#name')

pdf()

Tạo tệp PDF từ một trang. Bạn có thể

await page.pdf({ path: 'file.pdf })

Bạn có thể chuyển nhiều tùy chọn cho phương pháp này để thiết lập các chi tiết PDF đã tạo.Xem tài liệu chính thức.

reload()

Tải lại trang

await page.reload()

screenshot()

Chụp ảnh màn hình PNG của trang, lưu nó vào tên tệp đã chọn bằng cách sử dụngpath.

await page.screenshot({path: 'screenshot.png'})

Xem tất cả các tùy chọn

select()

Chọn các phần tử DOM được xác định bởi bộ chọn được chuyển làm tham số

await page.select('input#name')

setContent()

Bạn có thể đặt nội dung của một trang, thay vì mở một trang hiện có.

Hữu ích để tạo các tệp PDF hoặc ảnh chụp màn hình theo chương trình với HTML hiện có:

const html = '<h1>Hello!</h1>'
await page.setContent(html)
await page.pdf({path: 'hello.pdf'})
await page.screenshot({path: 'screenshot.png'})

setViewPort()

Theo mặc định, khung nhìn là 800x600px. Nếu bạn muốn có một khung nhìn khác, có thể để chụp ảnh màn hình, hãy gọisetViewporttruyền một đối tượng vớiwidthheighttính chất.

await page.setViewport({ width: 1280, height: 800 })

title()

Lấy tiêu đề trang

await page.title()

type()

Nhập vào một bộ chọn xác định một phần tử biểu mẫu

await page.type('input#name', 'Flavio')

Cácdelaytùy chọn cho phép mô phỏng thao tác nhập như người dùng trong thế giới thực, thêm độ trễ giữa mỗi ký tự:

await page.type('input#name', 'Flavio', {delay: 100})

url()

Lấy URL của trang

await page.url()

viewport()

Nhận chế độ xem trang

await page.viewport()

waitFor()

Chờ một cái gì đó cụ thể xảy ra. Có các chức năng phím tắt sau:

  • waitForFunction
  • waitForNavigation
  • waitForRequest
  • waitForResponse
  • waitForSelector
  • waitForXPath

Thí dụ:

await page.waitFor(waitForNameToBeFilled)
const waitForNameToBeFilled = () => page.$('input#name').value != ''

Không gian tên trang

Một đối tượng trang cung cấp cho bạn quyền truy cập vào một số đối tượng khác nhau:

Mỗi người trong số đó mở ra rất nhiều chức năng mới.

keyboardmousecó lẽ là những thứ bạn sẽ sử dụng nhiều nhất khi cố gắng tự động hóa mọi thứ.

Ví dụ: đây là cách bạn kích hoạt nhập vào một phần tử (lẽ ra phải được chọn trước đó):

await page.keyboard.type('hello!')

Các phương pháp bàn phím khác là

  • keyboard.down()gửi một sự kiện keydown
  • keyboard.press()để gửi một phím xuống, sau đó là một lần gõ phím (mô phỏng một loại phím thông thường). Được sử dụng chủ yếu cho các phím bổ trợ (shift, ctrl, cmd)
  • keyboard.sendCharacter()gửi một sự kiện nhấn phím
  • keyboard.type()gửi một sự kiện nhấn phím, nhấn phím và gõ phím
  • keyboard.up()để gửi một sự kiện keyup

Tất cả những người đó nhận được mã phím bàn phím như được xác định trong tệp Bố cục Bàn phím Hoa Kỳ:https://github.com/GoogleChrome/puppeteer/blob/master/lib/USKeyboardLayout.js. Các ký tự và số bình thường được nhập nguyên trạng, trong khi các khóa đặc biệt có mã đặc biệt để xác định chúng.

mouseđưa ra 4 phương pháp:

  • mouse.click()để mô phỏng một cú nhấp chuột:mousedownmouseupsự kiện
  • mouse.down()để mô phỏng mộtmousedownbiến cố
  • mouse.move()để di chuyển đến các tọa độ khác nhau
  • mouse.up()để mô phỏng mộtmouseupbiến cố