بدء استخدام Chrome بلا واجهة مستخدم رسومية

TL;DR

Chrome بلا واجهة مستخدم رسومية يشحن في Chrome 59. وهي طريقة لتشغيل متصفِّح Chrome في بيئة بلا واجهة مستخدم رسومية. في الأساس، الجري Chrome بدون Chrome! فهو يجمع جميع ميزات الأنظمة الأساسية للويب الحديثة بواسطة Chromium ومحرك عرض Blink إلى سطر الأوامر.

لماذا يعتبر ذلك مفيدًا؟

المتصفح بلا واجهة مستخدم رسومية هو أداة رائعة للاختبارات الآلية وبيئات الخادم التي لا تحتاج إلى هيكل واجهة مستخدم مرئي. على سبيل المثال، قد ترغب في إجراء بعض الاختبارات على صفحة ويب حقيقية، أو إنشاء ملف PDF، أو مجرد فحص كيفية عرض المتصفح لعنوان URL.

بداية بلا واجهة مستخدم رسومية (CLI)

أسهل طريقة لبدء استخدام وضع التشغيل بلا واجهة مستخدم رسومية هي فتح برنامج Chrome الثنائي. من سطر الأوامر. إذا كان لديك الإصدار 59 من Chrome أو الإصدارات الأحدث، يمكنك بدء 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. سيبدأ الموقع الدقيق من منصة إلى أخرى. نظرًا لاستخدامي لنظام التشغيل Mac، أنشأت أسماء مستعارة ملائمة لكل إصدار من إصدارات 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 من هنا.

ميزات سطر الأوامر

في بعض الحالات، قد لا تحتاج إلى كتابة نص برمجي آليًا لمتصفِّح 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 في دليل العمل الحالي. للحصول على لقطات شاشة كاملة للصفحة أكثر مشاركة. هناك مدونة رائعة مشاركة من ديفيد شنير التي ستساعدك. إتمام الدفع استخدام Chrome بلا واجهة مستخدم رسومية كأداة مبرمَجة لأخذ لقطات الشاشة .

وضع REPL (تكرار القراءة والتقييم)

تعمل العلامة --repl بلا واجهة مستخدم رسومية في وضع يمكنك من خلاله تقييم تعبيرات JavaScript. في المتصفح، مباشرةً من سطر الأوامر:

$ 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 بدون واجهة مستخدم للمتصفّح؟

عند تشغيل Chrome باستخدام --remote-debugging-port=9222، يتم بدء تشغيل نسخة افتراضية. مع تفعيل بروتوكول أدوات مطوّري البرامج. تشير رسالة الأشكال البيانية للاتصال بـ Chrome وتشغيل نظام التشغيل بلا واجهة مستخدم رسومية مثيل المتصفح. إنها أيضًا الطريقة التي تستخدمها أدوات مثل Sublime وVS Code وNode تصحيح أخطاء أحد التطبيقات عن بُعد. #synergy

بما أنّه ليس لديك واجهة مستخدم للمتصفّح للاطّلاع على الصفحة، انتقِل إلى http://localhost:9222. في متصفح آخر للتأكد من أن كل شيء يعمل. ستظهر لك قائمة الصفحات القابلة للفحص التي يمكنك فيها النقر عليها ومعرفة ما تعرضه "بلا واجهة مستخدم رسومية":

جهاز تحكُّم عن بُعد في أدوات مطوّري البرامج
واجهة المستخدم لتصحيح الأخطاء عن بُعد في "أدوات مطوّري البرامج"

من هنا، يمكنك استخدام ميزات "أدوات مطوّري البرامج" المألوفة لفحص المحتوى وتصحيح الأخطاء وضبط إعداداته الصفحة كما تفعل عادةً. إذا كنت تستخدم بلا واجهة مستخدم رسومية آليًا، أداة فعّالة لتصحيح الأخطاء والاستجابة لعرض جميع بروتوكولات أدوات مطوّري البرامج عبر السلك، والتواصل مع المتصفح.

استخدام (عقدة) آليًا

محرك العرائس

Puppeteer هو مكتبة عُقد التي طوّرها فريق Chrome توفّر واجهة برمجة تطبيقات عالية المستوى للتحكّم في المحتوى بلا واجهة مستخدم رسومية Chrome (أو الإصدار الكامل). وهو مشابه لمكتبات الاختبار الآلية الأخرى، مثل Phantom. و NightmareJS، ولكنها تعمل فقط مع أحدث إصدارات Chrome.

ويمكن استخدام Puppeteer لالتقاط لقطات شاشة وإنشاء ملفات PDF وغير ذلك التنقل بين الصفحات، وجلب معلومات حول تلك الصفحات. أنصحك بزيارة المكتبة إذا أردت اختبار المتصفح بشكل تلقائي وبسرعة. تخفي التعقيدات بروتوكول أدوات مطوري البرامج ويعتني بالمهام المتكررة مثل إطلاق مثيل تصحيح أخطاء Chrome.

تثبيته:

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();
})();

يمكنك الاطّلاع على مستندات Puppeteer. لمعرفة المزيد حول واجهة برمجة التطبيقات الكاملة.

مكتبة CRI

chrome-remote-interface هي مكتبة ذات مستوى أقل من واجهة برمجة تطبيقات Puppeteer. أوصي به إذا كنت تريد أن قريبًا من المعدن واستخدِم بروتوكول أدوات مطوّري البرامج مباشرةً.

إطلاق Chrome

لا تقوم واجهة chrome-عن بُعد بتشغيل Chrome نيابة عنك، لذا سيتعين عليك أخذ بذلك بنفسك.

في قسم واجهة سطر الأوامر، بدأنا تشغيل Chrome يدويًا باستخدام --headless --remote-debugging-port=9222 ومع ذلك، لإجراء الاختبارات بشكل تلقائي تمامًا، ربما تريد ظهور Chrome من تطبيقك.

إحدى الطرق هي استخدام 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) => {
  ...
});

ولكن الأمور تصبح صعبة إذا كنت ترغب في حل يمكن حمله بسهولة الأساسية. ما عليك سوى النظر إلى هذا المسار غير القابل للتغيير في Chrome :(

استخدام ChromeLauncher

إنّ لعبة Lighthouse مدهشة لاختبار جودة تطبيقات الويب. وحدة فعّالة لإطلاقها تم تطوير Chrome ضمن أداة Lighthouse ويتم استخراجه الآن للاستخدام المستقل. وحدة NPM chrome-launcher سيتم العثور على مكان تثبيت Chrome وإعداد مثيل تصحيح الأخطاء وبدء تشغيل المتصفّح وإيقافه عند الانتهاء من البرنامج. أفضل جزء هو أنها تعمل عبر أنظمة أساسية مختلفة بفضل عقدة!

بشكل تلقائي، سيحاول chrome-launcher تشغيل Chrome Canary (إذا كان مثبت)، ولكن يمكنك تغيير ذلك لتحديد Chrome الذي تريد استخدامه يدويًا. إلى استخدمه، قم بالتثبيت أولاً من npm:

npm i --save chrome-launcher

مثال: استخدام chrome-launcher لتشغيل النسخة بلا واجهة مستخدم رسومية

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 في ميزة "إدارة المهام" التي حمَّلت about:blank. تذكر، هناك لن تكون أي واجهة مستخدم للمتصفح. نحن بلا واجهة مستخدم رسومية.

يجب استخدام بروتوكول "أدوات مطوري البرامج" للتحكّم في المتصفّح.

جارٍ استرداد معلومات حول الصفحة

لنبدأ في تثبيت المكتبة:

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> للصفحة باستخدام واجهات برمجة تطبيقات 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.
});

})();

استخدام Selenium وWebDriver وChromeDriver

في الوقت الحالي، يفتح سيلينيوم مثيلاً كاملاً من Chrome. بعبارة أخرى، إنها تلقائيًا ولكن ليس بلا واجهة مستخدم رسومية تمامًا. ومع ذلك، يمكن أن يكون السيلينيوم مهيأ لتشغيل Chrome بلا واجهة مستخدم رسومية مع قليل من العمل. أنصح به تشغيل السيلينيوم باستخدام متصفِّح Chrome بلا واجهة مستخدم رسومية إذا كنت تريد التعليمات الكاملة حول كيفية إعداد الجهاز بنفسك، ولكنني شاركتُ بعض الأمثلة أدناه لتبدأ.

استخدام ChromeDriver

ChromeDriver 2.32 يستخدم Chrome 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 هي واجهة برمجة تطبيقات ذات مستوى أعلى بالإضافة إلى 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();

})();

موارد أخرى

وفي ما يلي بعض الموارد المفيدة لمساعدتك على البدء:

مستندات Google

الأدوات

  • chrome-remote-interface - العقدة التي تتضمّن بروتوكول "أدوات مطوّري البرامج"
  • Lighthouse - أداة آلية للاختبار وجودة تطبيق الويب تستخدم البروتوكول بشكل مكثّف
  • chrome-launcher - وحدة العقدة الخاصة بتشغيل Chrome، وهو جاهز للتشغيل الآلي

إصدارات تجريبية

الأسئلة الشائعة

هل أحتاج إلى علامة --disable-gpu؟

على نظام التشغيل Windows فقط. لم تعُد الأنظمة الأساسية الأخرى تتطلب هذا الإجراء. العلامة --disable-gpu هي أو حل مؤقت لبعض الأخطاء. لن تحتاج إلى هذه العلامة في الإصدارات المستقبلية من Chrome. لمزيد من المعلومات، يمكنك الاطّلاع على crbug.com/737678. لمزيد من المعلومات.

هل ما زلت بحاجة إلى Xvfb؟

لا، إذ لا يستخدم Chrome بلا واجهة مستخدم رسومية نافذة، ولذلك لا يستخدم خادم عرض مثل Xvfb لم تعد هناك حاجة إليه. يمكنك إجراء اختباراتك المبرمَجة بدونها بنجاح.

ما هو Xvfb؟ Xvfb هو خادم عرض في الذاكرة للأنظمة الشبيهة بـ Unix ويتيح لك لتشغيل تطبيقات رسومية (مثل Chrome) بدون شاشة عرض فعلية. يستخدم العديد من الأشخاص Xvfb لتشغيل إصدارات سابقة من Chrome لتنفيذ "بلا واجهة مستخدم رسومية" اختبار الفرضية.

كيف يمكنني إنشاء حاوية Docker تشغّل Chrome بلا واجهة مستخدم رسومية؟

اطّلع على منارة-ci. تحتوي على مثال على ملف Dock التي تستخدم node:8-slim كصورة أساسية، يتم تثبيت + تشغيل Lighthouse على App Engine Flex.

هل يمكنني استخدام هذا مع Selenium / WebDriver / ChromeDriver؟

نعم. راجِع استخدام Selenium وWebDriver وChromeDriver.

ما علاقة ذلك بتطبيق PhantomJS؟

إنّ متصفِّح Chrome بلا واجهة مستخدم رسومية يشبه أدوات مثل PhantomJS. كلاهما يمكن استخدامها للاختبار الآلي في بيئة بلا واجهة مستخدم رسومية. الاختلاف الرئيسي بين الاثنين هو أن Phantom تستخدم إصدارًا قديمًا من WebKit لعرض بينما يستخدم Chrome بلا واجهة مستخدم رسومية أحدث إصدار من Blink.

في الوقت الحالي، يوفّر Phantom أيضًا واجهة برمجة تطبيقات بمستوى أعلى من بروتوكول أدوات مطوّري البرامج.

أين يمكنني الإبلاغ عن الأخطاء؟

للإبلاغ عن الأخطاء في Chrome بلا واجهة مستخدم رسومية، يُرجى الإبلاغ عنها على crbug.com.

بالنسبة إلى الأخطاء في بروتوكول أدوات مطوّري البرامج، يُرجى تقديمها على github.com/ChromeDevTools/devtools-protocol.