شروع کار با Headless Chrome

TL; DR

Headless Chrome در Chrome 59 ارسال می شود. این راهی برای اجرای مرورگر Chrome در یک محیط بدون هد است. در اصل، اجرای کروم بدون کروم! تمام ویژگی های پلت فرم وب مدرن ارائه شده توسط Chromium و موتور رندر Blink را به خط فرمان می آورد.

چرا مفید است؟

یک مرورگر هدلس ابزاری عالی برای تست خودکار و محیط های سرور است که در آن به پوسته رابط کاربری قابل مشاهده نیاز ندارید. به عنوان مثال، ممکن است بخواهید چند آزمایش را بر روی یک صفحه وب واقعی انجام دهید، یک PDF از آن ایجاد کنید، یا فقط بررسی کنید که مرورگر چگونه یک URL را ارائه می دهد.

شروع هدلس (CLI)

ساده ترین راه برای شروع با حالت بدون سر، باز کردن باینری کروم از خط فرمان است. اگر Chrome 59+ را نصب کرده‌اید، Chrome را با پرچم --headless راه‌اندازی کنید:

chrome \
--headless \                   # Runs Chrome in headless mode.
--disable-gpu \                # Temporarily needed if running on Windows.
--remote-debugging-port=9222 \
https://www.chromestatus.com   # URL to open. Defaults to about:blank.

chrome باید به نصب Chrome شما اشاره کند. مکان دقیق از پلت فرمی به پلتفرم دیگر متفاوت خواهد بود. از آنجایی که من در مک هستم، برای هر نسخه کروم که نصب کرده ام، نام مستعار مناسبی ایجاد کردم.

اگر در کانال پایدار کروم هستید و نمی توانید نسخه بتا را دریافت کنید، توصیه می کنم chrome-canary استفاده کنید:

alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
alias chrome-canary="/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary"
alias chromium="/Applications/Chromium.app/Contents/MacOS/Chromium"

Chrome Canary را از اینجا دانلود کنید.

ویژگی های خط فرمان

در برخی موارد، ممکن است نیازی به اسکریپت برنامه‌نویسی Headless Chrome نداشته باشید. چند پرچم خط فرمان مفید برای انجام وظایف رایج وجود دارد.

چاپ DOM

پرچم --dump-dom document.body.innerHTML را در stdout چاپ می کند:

    chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/

یک PDF ایجاد کنید

پرچم --print-to-pdf یک PDF از صفحه ایجاد می کند:

chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/

گرفتن اسکرین شات

برای گرفتن اسکرین شات از یک صفحه، از پرچم --screenshot استفاده کنید:

chrome --headless --disable-gpu --screenshot https://www.chromestatus.com/

# Size of a standard letterhead.
chrome --headless --disable-gpu --screenshot --window-size=1280,1696 https://www.chromestatus.com/

# Nexus 5x
chrome --headless --disable-gpu --screenshot --window-size=412,732 https://www.chromestatus.com/

اجرای با --screenshot فایلی به نام screenshot.png در فهرست کاری فعلی تولید می کند. اگر به دنبال اسکرین شات های تمام صفحه هستید، همه چیز کمی بیشتر درگیر است. یک پست وبلاگ عالی از دیوید شنور وجود دارد که شما را پوشش داده است. بررسی استفاده از کروم بدون هد به‌عنوان یک ابزار خودکار عکس‌برداری از صفحه نمایش .

حالت REPL (حلقه خواندن، ارزیابی، چاپ)

پرچم --repl در حالتی Headless اجرا می شود که می توانید عبارات JS را در مرورگر، درست از خط فرمان ارزیابی کنید:

$ chrome --headless --disable-gpu --repl --crash-dumps-dir=./tmp https://www.chromestatus.com/
[0608/112805.245285:INFO:headless_shell.cc(278)] Type a Javascript expression to evaluate or "quit" to exit.
>>> location.href
{"result":{"type":"string","value":"https://www.chromestatus.com/features"}}
>>> quit
$

کروم را بدون رابط کاربری مرورگر اشکال زدایی می کنید؟

وقتی Chrome را با --remote-debugging-port=9222 اجرا می کنید، نمونه ای را با فعال بودن پروتکل DevTools شروع می کند. این پروتکل برای برقراری ارتباط با کروم و هدایت نمونه مرورگر بدون هد استفاده می شود. همچنین ابزارهایی مانند Sublime، VS Code و Node برای اشکال زدایی از راه دور یک برنامه استفاده می کنند. #هم افزایی

از آنجایی که رابط کاربری مرورگر برای دیدن صفحه ندارید، در مرورگر دیگری به http://localhost:9222 بروید تا بررسی کنید که همه چیز کار می کند. لیستی از صفحات قابل بازرسی را مشاهده می کنید که می توانید روی آنها کلیک کنید و ببینید Headless چه چیزی را ارائه می دهد:

DevTools Remote
رابط کاربری اشکال زدایی از راه دور DevTools

از اینجا، می‌توانید از ویژگی‌های آشنای DevTools برای بازرسی، اشکال‌زدایی، و تنظیم صفحه مانند حالت عادی استفاده کنید. اگر به صورت برنامه‌نویسی از Headless استفاده می‌کنید، این صفحه همچنین یک ابزار اشکال‌زدایی قدرتمند برای مشاهده تمام دستورات پروتکل DevTools خام است که از طریق سیم عبور می‌کنند و با مرورگر ارتباط برقرار می‌کنند.

استفاده از طریق برنامه (Node)

عروسک گردان

Puppeteer یک کتابخانه Node است که توسط تیم Chrome توسعه یافته است. این یک API سطح بالا برای کنترل Chrome بدون هد (یا کامل) ارائه می دهد. این شبیه به دیگر کتابخانه‌های تست خودکار مانند Phantom و NightmareJS است، اما فقط با آخرین نسخه‌های کروم کار می‌کند.

از جمله موارد دیگر، Puppeteer را می توان برای گرفتن اسکرین شات، ایجاد PDF، پیمایش صفحات و واکشی اطلاعات در مورد آن صفحات استفاده کرد. اگر می‌خواهید تست مرورگر را به سرعت خودکار کنید، کتابخانه را توصیه می‌کنم. پیچیدگی‌های پروتکل DevTools را پنهان می‌کند و از کارهای اضافی مانند راه‌اندازی نمونه اشکال‌زدایی کروم مراقبت می‌کند.

نصبش کن:

npm i --save puppeteer

مثال - عامل کاربر را چاپ کنید

const puppeteer = require('puppeteer');

(async() => {
  const browser = await puppeteer.launch();
  console.log(await browser.version());
  await browser.close();
})();

مثال - گرفتن اسکرین شات از صفحه

const puppeteer = require('puppeteer');

(async() => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://www.chromestatus.com', {waitUntil: 'networkidle2'});
  await page.pdf({path: 'page.pdf', format: 'A4'});

  await browser.close();
})();

برای کسب اطلاعات بیشتر در مورد API کامل، مستندات Puppeteer را بررسی کنید.

کتابخانه CRI

chrome-remote-interface یک کتابخانه سطح پایین تر از API Puppeteer است. اگر می خواهید به فلز نزدیک شوید و مستقیماً از پروتکل DevTools استفاده کنید، توصیه می کنم.

در حال راه اندازی کروم

chrome-remote-interface Chrome را برای شما راه‌اندازی نمی‌کند، بنابراین باید خودتان مراقب آن باشید.

در بخش CLI، کروم را به صورت دستی با استفاده از --headless --remote-debugging-port=9222 راه اندازی کردیم. با این حال، برای خودکارسازی کامل تست‌ها، احتمالاً می‌خواهید کروم را از برنامه خود ایجاد کنید.

یک راه استفاده از child_process است:

const execFile = require('child_process').execFile;

function launchHeadlessChrome(url, callback) {
  // Assuming MacOSx.
  const CHROME = '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome';
  execFile(CHROME, ['--headless', '--disable-gpu', '--remote-debugging-port=9222', url], callback);
}

launchHeadlessChrome('https://www.chromestatus.com', (err, stdout, stderr) => {
  ...
});

اما اگر راه حل قابل حملی را بخواهید که در چندین پلتفرم کار می کند، دشوار می شود. فقط به مسیر سخت کد شده کروم نگاه کنید:(

با استفاده از ChromeLauncher

Lighthouse یک ابزار شگفت انگیز برای آزمایش کیفیت برنامه های وب شما است. یک ماژول قوی برای راه‌اندازی Chrome در Lighthouse توسعه داده شد و اکنون برای استفاده مستقل استخراج شده است. ماژول chrome-launcher NPM محل نصب کروم را پیدا می کند، نمونه اشکال زدایی را راه اندازی می کند، مرورگر را راه اندازی می کند و پس از اتمام برنامه، آن را می کشد. بهترین بخش این است که به لطف Node در چند پلتفرم کار می کند!

به‌طور پیش‌فرض، chrome-launcher سعی می‌کند Chrome Canary را راه‌اندازی کند (اگر نصب باشد)، اما می‌توانید آن را تغییر دهید تا به‌طور دستی انتخاب کنید از کدام Chrome استفاده کنید. برای استفاده از آن، ابتدا از npm نصب کنید:

npm i --save chrome-launcher

مثال - استفاده از chrome-launcher برای راه‌اندازی Headless

const chromeLauncher = require('chrome-launcher');

// Optional: set logging level of launcher to see its output.
// Install it using: npm i --save lighthouse-logger
// const log = require('lighthouse-logger');
// log.setLevel('info');

/**
 * Launches a debugging instance of Chrome.
 * @param {boolean=} headless True (default) launches Chrome in headless mode.
 *     False launches a full version of Chrome.
 * @return {Promise<ChromeLauncher>}
 */
function launchChrome(headless=true) {
  return chromeLauncher.launch({
    // port: 9222, // Uncomment to force a specific port of your choice.
    chromeFlags: [
      '--window-size=412,732',
      '--disable-gpu',
      headless ? '--headless' : ''
    ]
  });
}

launchChrome().then(chrome => {
  console.log(`Chrome debuggable on port: ${chrome.port}`);
  ...
  // chrome.kill();
});

اجرای این اسکریپت کار زیادی انجام نمی دهد، اما باید نمونه ای از Chrome را مشاهده کنید که در Task Manager بارگذاری شده است about:blank . به یاد داشته باشید، هیچ رابط کاربری مرورگری وجود نخواهد داشت. ما بی سر هستیم

برای کنترل مرورگر به پروتکل DevTools نیاز داریم!

بازیابی اطلاعات در مورد صفحه

بیایید کتابخانه را نصب کنیم:

npm i --save chrome-remote-interface
نمونه ها

مثال - عامل کاربر را چاپ کنید

const CDP = require('chrome-remote-interface');

...

launchChrome().then(async chrome => {
  const version = await CDP.Version({port: chrome.port});
  console.log(version['User-Agent']);
});

نتایج چیزی شبیه به: HeadlessChrome/60.0.3082.0

مثال - بررسی کنید که آیا سایت دارای مانیفست برنامه وب است یا خیر

const CDP = require('chrome-remote-interface');

...

(async function() {

const chrome = await launchChrome();
const protocol = await CDP({port: chrome.port});

// Extract the DevTools protocol domains we need and enable them.
// See API docs: https://chromedevtools.github.io/devtools-protocol/
const {Page} = protocol;
await Page.enable();

Page.navigate({url: 'https://www.chromestatus.com/'});

// Wait for window.onload before doing stuff.
Page.loadEventFired(async () => {
  const manifest = await Page.getAppManifest();

  if (manifest.url) {
    console.log('Manifest: ' + manifest.url);
    console.log(manifest.data);
  } else {
    console.log('Site has no app manifest');
  }

  protocol.close();
  chrome.kill(); // Kill Chrome.
});

})();

مثال - <title> صفحه را با استفاده از APIهای DOM استخراج کنید.

const CDP = require('chrome-remote-interface');

...

(async function() {

const chrome = await launchChrome();
const protocol = await CDP({port: chrome.port});

// Extract the DevTools protocol domains we need and enable them.
// See API docs: https://chromedevtools.github.io/devtools-protocol/
const {Page, Runtime} = protocol;
await Promise.all([Page.enable(), Runtime.enable()]);

Page.navigate({url: 'https://www.chromestatus.com/'});

// Wait for window.onload before doing stuff.
Page.loadEventFired(async () => {
  const js = "document.querySelector('title').textContent";
  // Evaluate the JS expression in the page.
  const result = await Runtime.evaluate({expression: js});

  console.log('Title of page: ' + result.result.value);

  protocol.close();
  chrome.kill(); // Kill Chrome.
});

})();

با استفاده از سلنیوم، WebDriver، و ChromeDriver

در حال حاضر، سلنیوم یک نمونه کامل از کروم را باز می کند. به عبارت دیگر، این یک راه حل خودکار است اما کاملاً بدون سر نیست. با این حال، سلنیوم را می‌توان برای اجرای کروم بدون هد با کمی کار پیکربندی کرد. اگر می‌خواهید دستورالعمل‌های کاملی را در مورد نحوه تنظیم کارها به دست خودتان ارائه کنید، اجرای سلنیوم با هدلس کروم را توصیه می‌کنم، اما برای شروع به شما چند نمونه را در زیر آورده‌ام.

با استفاده از ChromeDriver

ChromeDriver 2.32 از کروم 61 استفاده می کند و با Chrome هدلس به خوبی کار می کند.

نصب کنید:

npm i --save-dev selenium-webdriver chromedriver

مثال:

const fs = require('fs');
const webdriver = require('selenium-webdriver');
const chromedriver = require('chromedriver');

const chromeCapabilities = webdriver.Capabilities.chrome();
chromeCapabilities.set('chromeOptions', {args: ['--headless']});

const driver = new webdriver.Builder()
  .forBrowser('chrome')
  .withCapabilities(chromeCapabilities)
  .build();

// Navigate to google.com, enter a search.
driver.get('https://www.google.com/');
driver.findElement({name: 'q'}).sendKeys('webdriver');
driver.findElement({name: 'btnG'}).click();
driver.wait(webdriver.until.titleIs('webdriver - Google Search'), 1000);

// Take screenshot of results page. Save to disk.
driver.takeScreenshot().then(base64png => {
  fs.writeFileSync('screenshot.png', new Buffer(base64png, 'base64'));
});

driver.quit();

با استفاده از WebDriverIO

WebDriverIO یک API سطح بالاتر در بالای Selenium WebDriver است.

نصب کنید:

npm i --save-dev webdriverio chromedriver

مثال: ویژگی‌های CSS را در chromestatus.com فیلتر کنید

const webdriverio = require('webdriverio');
const chromedriver = require('chromedriver');

const PORT = 9515;

chromedriver.start([
  '--url-base=wd/hub',
  `--port=${PORT}`,
  '--verbose'
]);

(async () => {

const opts = {
  port: PORT,
  desiredCapabilities: {
    browserName: 'chrome',
    chromeOptions: {args: ['--headless']}
  }
};

const browser = webdriverio.remote(opts).init();

await browser.url('https://www.chromestatus.com/features');

const title = await browser.getTitle();
console.log(`Title: ${title}`);

await browser.waitForText('.num-features', 3000);
let numFeatures = await browser.getText('.num-features');
console.log(`Chrome has ${numFeatures} total features`);

await browser.setValue('input[type="search"]', 'CSS');
console.log('Filtering features...');
await browser.pause(1000);

numFeatures = await browser.getText('.num-features');
console.log(`Chrome has ${numFeatures} CSS features`);

const buffer = await browser.saveScreenshot('screenshot.png');
console.log('Saved screenshot...');

chromedriver.stop();
browser.end();

})();

منابع بیشتر

در اینجا چند منبع مفید برای شروع شما آورده شده است:

اسناد

ابزار

  • chrome-remote-interface - ماژول گره ای که پروتکل DevTools را می پوشاند
  • Lighthouse - ابزار خودکار برای آزمایش کیفیت برنامه وب؛ به شدت از پروتکل استفاده می کند
  • chrome-launcher - ماژول گره برای راه اندازی Chrome، آماده برای اتوماسیون

دموها

  • " وب بدون سر " - پست وبلاگ عالی پل کینلان در مورد استفاده از Headless با api.ai.

سوالات متداول

آیا به پرچم --disable-gpu نیاز دارم؟

فقط روی ویندوز پلتفرم های دیگر دیگر به آن نیاز ندارند. پرچم --disable-gpu یک کار موقت برای چند باگ است. در نسخه های بعدی کروم به این پرچم نیازی نخواهید داشت. برای اطلاعات بیشتر به crbug.com/737678 مراجعه کنید.

پس من هنوز به Xvfb نیاز دارم؟

خیر. Headless Chrome از پنجره استفاده نمی‌کند، بنابراین دیگر به سرور نمایشگر مانند Xvfb نیازی نیست. با خوشحالی می توانید تست های خودکار خود را بدون آن اجرا کنید.

Xvfb چیست؟ Xvfb یک سرور نمایشگر درون حافظه برای سیستم های یونیکس مانند است که به شما امکان می دهد برنامه های گرافیکی (مانند کروم) را بدون نمایشگر فیزیکی متصل اجرا کنید. بسیاری از مردم از Xvfb برای اجرای نسخه‌های قبلی کروم برای انجام آزمایش بدون سر استفاده می‌کنند.

چگونه می توانم یک ظرف Docker ایجاد کنم که هدلس کروم را اجرا کند؟

فانوس دریایی-ci را بررسی کنید. یک نمونه Dockerfile دارد که از node:8-slim به عنوان تصویر پایه استفاده می کند، Lighthouse را روی App Engine Flex نصب می کند + اجرا می کند .

آیا می توانم از این با Selenium / WebDriver / ChromeDriver استفاده کنم ؟

بله. به استفاده از سلنیوم، WebDriver و ChromeDriver مراجعه کنید.

این چه ارتباطی با PhantomJS دارد؟

هدلس کروم شبیه ابزارهایی مانند PhantomJS است. هر دو را می توان برای آزمایش خودکار در یک محیط بدون هد استفاده کرد. تفاوت اصلی بین این دو این است که Phantom از نسخه قدیمی WebKit به عنوان موتور رندر خود استفاده می کند در حالی که Headless Chrome از آخرین نسخه Blink استفاده می کند.

در حال حاضر، Phantom همچنین یک API سطح بالاتری نسبت به پروتکل DevTools ارائه می دهد.

کجا اشکالات را گزارش کنم؟

برای اشکالات مربوط به Headless Chrome، آنها را در crbug.com ثبت کنید.

برای اشکالات موجود در پروتکل DevTools، آنها را در github.com/ChromeDevTools/devtools-protocol ثبت کنید.