Diterbitkan 4 Juni 2018 di blog perusahaan tanpa browser.Kami senang mengumumkan bahwa kami baru saja melewati garis
dua juta sesi yang dilayani ! Ini adalah
jutaan tangkapan layar yang dihasilkan, cetak PDF dan situs yang diuji. Kami telah melakukan hampir semua yang dapat Anda pikirkan dengan browser tanpa kepala.
Meskipun itu bagus untuk mencapai tonggak sejarah, tetapi dalam perjalanan jelas ada
banyak tumpang tindih dan masalah. Karena banyaknya lalu lintas yang diterima, saya ingin mengambil langkah mundur dan menyatakan rekomendasi umum untuk meluncurkan browser tanpa kepala (dan
dalang ) dalam produksi.
Berikut ini beberapa tipsnya.
1. Jangan menggunakan browser tanpa kepala sama sekali

Konsumsi Sumber Daya Chrome Tanpa Kepala
Sama sekali tidak, jika
keadaan memungkinkan,
jangan memulai browser sama sekali dalam mode tanpa kepala . Terutama pada infrastruktur yang sama dengan aplikasi Anda (lihat di atas). Browser tanpa kepala tidak dapat diprediksi, rakus dan berkembang biak seperti Mr. Misix dari Rick dan Morty. Hampir semua yang dapat dilakukan browser (kecuali untuk interpolasi dan menjalankan JavaScript) dapat dilakukan dengan menggunakan alat Linux sederhana. Perpustakaan Cheerio dan lainnya menawarkan Node API yang elegan untuk mengambil data dengan permintaan dan pengikisan HTTP, jika itu adalah tujuan Anda.
Misalnya, Anda dapat mengambil halaman (dengan asumsi itu semacam HTML) dan memo dengan perintah sederhana seperti ini:
import cheerio from 'cheerio'; import fetch from 'node-fetch'; async function getPrice(url) { const res = await fetch(url); const html = await res.test(); const $ = cheerio.load(html); return $('buy-now.price').text(); } getPrice('https://my-cool-website.com/');
Jelas, skrip tidak mencakup semua kasus penggunaan, dan jika Anda membaca artikel ini, maka kemungkinan besar Anda harus menggunakan browser tanpa kepala. Jadi mari kita mulai.
2. Jangan meluncurkan browser tanpa kepala secara tidak perlu
Kami telah menjumpai banyak pengguna yang mencoba menjaga peramban tetap berjalan meskipun tidak digunakan (dengan koneksi terbuka). Meskipun ini mungkin strategi yang baik untuk mempercepat sesi, itu akan macet dalam beberapa jam. Sebagian besar karena browser
suka men
- cache semuanya dalam satu baris dan secara bertahap memakan memori. Segera setelah Anda berhenti menggunakan browser secara intensif, segera tutup!
import puppeteer from 'puppeteer'; async function run() { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://www.example.com/');
Di browserless, kami biasanya memperbaiki sendiri kesalahan ini untuk pengguna, selalu mengatur semacam waktu untuk sesi dan menutup browser saat WebSocket terputus. Tetapi jika Anda tidak menggunakan
layanan kami atau
gambar Docker cadangan , pastikan untuk memastikan bahwa Anda
secara otomatis menutup browser, karena itu akan tidak menyenangkan ketika semuanya jatuh di tengah malam.
3. Halaman teman Anda. page.evaluate
Hati-hati dengan transponder seperti babel atau naskah, karena mereka suka membuat fungsi pembantu dan menganggap bahwa mereka dapat diakses dengan penutupan. Artinya, panggilan balik .evaluate mungkin tidak berfungsi dengan benar.
Dalang memiliki banyak metode bagus, seperti menyimpan pemilih DOM dan hal-hal lain di lingkungan Node. Meskipun sangat nyaman, Anda dapat dengan mudah menembak diri sendiri jika ada sesuatu di halaman yang memaksa simpul DOM ini untuk
bermutasi . Ini mungkin tidak terlalu keren, tetapi pada kenyataannya lebih baik melakukan semua pekerjaan di sisi browser
dalam konteks browser . Ini biasanya berarti memuat
page.evaulate
untuk semua pekerjaan yang perlu dilakukan.
Misalnya, alih-alih sesuatu seperti ini (
tiga tindakan asinkron):
const $anchor = await page.$('a.buy-now'); const link = await $anchor.getProperty('href'); await $anchor.click(); return link;
Lebih baik melakukan ini (satu tindakan asinkron):
await page.evaluate(() => { const $anchor = document.querySelector('a.buy-now'); const text = $anchor.href; $anchor.click(); });
Keuntungan lain untuk membungkus tindakan dalam panggilan
evaluate
adalah portabilitas: kode ini dapat dijalankan di browser untuk memverifikasi alih-alih mencoba menulis ulang kode Node. Tentu saja, selalu disarankan untuk
menggunakan debugger untuk mengurangi waktu pengembangan.
Aturan praktis yang sederhana adalah menghitung jumlah
await
atau
then
dalam kode. Jika ada lebih dari satu, maka mungkin yang terbaik adalah menjalankan kode di dalam
page.evaluate
.
page.evaluate
panggilan. Alasannya adalah bahwa semua tindakan async bolak-balik antara Node runtime dan browser, yang berarti serialisasi dan deserialisasi JSON yang konstan. Meskipun tidak ada jumlah parsing yang begitu besar (karena semuanya didukung oleh WebSockets), masih membutuhkan waktu, yang lebih baik dihabiskan untuk hal lain.
4. Paralelkan browser, bukan halaman web
Jadi, kami menyadari bahwa meluncurkan browser tidak baik dan kami perlu melakukan ini hanya dalam keadaan darurat. Kiat berikutnya adalah menjalankan hanya satu sesi per browser. Meskipun pada kenyataannya adalah mungkin untuk menghemat sumber daya dengan memparalelkan kerja melalui
pages
, tetapi jika satu halaman jatuh, itu dapat merusak seluruh browser. Selain itu, tidak dijamin bahwa setiap halaman benar-benar bersih (cookie dan penyimpanan dapat menjadi sakit kepala,
seperti yang kita lihat ).
Sebaliknya:
import puppeteer from 'puppeteer';
Lebih baik lakukan ini:
import puppeteer from 'puppeteer'; const runJob = async (url) {
Setiap instance browser baru mendapatkan
--user-data-dir
(
kecuali jika dinyatakan lain ). Artinya, itu sepenuhnya diproses sebagai sesi baru yang baru. Jika Chrome macet karena suatu alasan, Chrome tidak akan melakukan sesi lain dengannya.
5. Batasan antrian dan konkurensi
Salah satu fitur utama dari browserless adalah kemampuan untuk membatasi paralelisasi dan antrian dengan rapi. Jadi aplikasi klien hanya menjalankan
puppeteer.connect
, tetapi mereka tidak memikirkan implementasi antrian. Ini mencegah sejumlah besar masalah, terutama dengan Chrome bersamaan yang melahap semua sumber daya yang tersedia dari aplikasi Anda.
Cara terbaik dan termudah adalah mengambil gambar Docker kami dan menjalankannya dengan parameter yang diperlukan:
# Pull in Puppeteer@1.4.0 support $ docker pull browserless/chrome:release-puppeteer-1.4.0 $ docker run -e "MAX_CONCURRENT_SESSIONS=10" browserless/chrome:release-puppeteer-1.4.0
Ini membatasi jumlah permintaan bersamaan hingga sepuluh (termasuk sesi debugging dan banyak lagi). Antrian dikonfigurasi oleh variabel
MAX_QUEUE_LENGTH
. Biasanya, Anda dapat melakukan sekitar 10 permintaan bersamaan per gigabyte memori. Persentase penggunaan CPU dapat bervariasi untuk tugas yang berbeda, tetapi pada dasarnya Anda akan membutuhkan banyak dan banyak RAM.
6. Jangan lupa tentang page.waitForNavigation
Salah satu masalah paling umum yang kami temui adalah tindakan yang mulai memuat halaman dengan penghentian skrip mendadak berikutnya. Ini karena tindakan yang memicu
pageload
sering menyebabkan menelan pekerjaan berikutnya. Untuk menyelesaikan masalah, Anda biasanya perlu memanggil tindakan memuat halaman - dan segera setelah itu menunggu untuk memuat.
Misalnya,
console.log
tersebut tidak berfungsi di satu tempat (
lihat demo ):
await page.goto('https://example.com'); await page.click('a'); const title = await page.title(); console.log(title);
Tapi itu
berfungsi di yang lain (
lihat demo ).
await page.goto('https://example.com'); page.click('a'); await page.waitForNavigation(); const title = await page.title(); console.log(title);
Anda dapat membaca lebih lanjut tentang waitForNavigation di
sini . Fungsi ini memiliki kira-kira parameter antarmuka yang sama seperti
page.goto
, tetapi hanya dengan bagian "tunggu".
7. Gunakan Docker untuk semua yang Anda butuhkan.
Chrome membutuhkan banyak dependensi untuk berfungsi dengan baik. Sangat banyak. Bahkan setelah menginstal semua yang Anda perlu khawatir tentang hal-hal seperti font dan proses phantom. Karenanya, sangat ideal untuk menggunakan semacam wadah untuk meletakkan semuanya di sana. Docker hampir secara khusus dirancang untuk tugas ini, karena Anda dapat membatasi jumlah sumber daya yang tersedia dan mengisolasinya. Jika Anda ingin membuat
Dockerfile
Anda sendiri, periksa di bawah ini semua dependensi yang diperlukan:
# Dependencies needed for packages downstream RUN apt-get update && apt-get install -y \ unzip \ fontconfig \ locales \ gconf-service \ libasound2 \ libatk1.0-0 \ libc6 \ libcairo2 \ libcups2 \ libdbus-1-3 \ libexpat1 \ libfontconfig1 \ libgcc1 \ libgconf-2-4 \ libgdk-pixbuf2.0-0 \ libglib2.0-0 \ libgtk-3-0 \ libnspr4 \ libpango-1.0-0 \ libpangocairo-1.0-0 \ libstdc++6 \ libx11-6 \ libx11-xcb1 \ libxcb1 \ libxcomposite1 \ libxcursor1 \ libxdamage1 \ libxext6 \ libxfixes3 \ libxi6 \ libxrandr2 \ libxrender1 \ libxss1 \ libxtst6 \ ca-certificates \ fonts-liberation \ libappindicator1 \ libnss3 \ lsb-release \ xdg-utils \ wget
Dan untuk menghindari proses zombie (hal yang umum di Chrome), lebih baik menggunakan sesuatu seperti
dumb-init untuk berjalan dengan benar:
ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 /usr/local/bin/dumb-init RUN chmod +x /usr/local/bin/dumb-init
Jika Anda ingin tahu lebih banyak, lihat
Dockerfile kami .
8. Ingat dua runtime yang berbeda.
Sangat berguna untuk mengingat bahwa ada
dua runtime JavaScript (Node dan browser). Ini bagus untuk memisahkan tugas, tetapi kebingungan pasti terjadi karena beberapa metode akan memerlukan melewati tautan eksplisit alih-alih hoisting.
Misalnya, ambil
page.evaluate
. Jauh di dalam perut protokol ada
pengetatan literal fungsi dan transfernya ke Chrome . Karena itu, hal-hal seperti penutupan dan lift
tidak akan berfungsi sama sekali . Jika Anda perlu memberikan beberapa referensi atau nilai ke panggilan evaluasi, tambahkan saja sebagai argumen yang akan diproses dengan benar.
Jadi, alih-alih merujuk
selector
melalui penutupan:
const anchor = 'a'; await page.goto('https://example.com/');
Parameter lulus yang lebih baik:
const anchor = 'a'; await page.goto('https://example.com/');
page.evaluate
dapat menambahkan satu atau lebih argumen ke fungsi
page.evaluate
, karena variabel di sini. Pastikan untuk memanfaatkan ini!
Masa depan
Kami sangat optimis tentang masa depan browser tanpa kepala dan semua otomatisasi yang dapat mereka capai. Menggunakan alat canggih seperti dalang dan tanpa browser, kami berharap bahwa debugging dan menjalankan otomatisasi tanpa kepala dalam produksi akan lebih mudah dan lebih cepat. Segera kami akan meluncurkan
penagihan pay-as-you-go untuk akun dan
fungsi yang akan membantu Anda mengatasi pekerjaan tanpa kepala Anda dengan lebih baik!