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
على تشغيل 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 بدون واجهة مستخدم المتصفّح؟
عند تشغيل Chrome باستخدام --remote-debugging-port=9222
، يتم تشغيل مثيل
مع تفعيل بروتوكول أدوات مطوّري البرامج. يُستخدَم بروتوكول
للتواصل مع Chrome وتشغيل مثيل المتصفّح
بلا واجهة مستخدم. وهي أيضًا الطريقة التي تستخدمها أدوات مثل Sublime وVS Code وNode ل debugging عن بُعد لتطبيق ما. #synergy
بما أنّه لا تتوفّر لديك واجهة مستخدم للمتصفّح لعرض الصفحة، انتقِل إلى http://localhost:9222
في متصفّح آخر للتأكّد من أنّ كل شيء يعمل على ما يرام. ستظهر لك قائمة ب
الصفحات القابلة للفحص التي يمكنك النقر عليها والاطّلاع على ما تعرِضه أداة Headless:
من هنا، يمكنك استخدام ميزات أدوات المطوّرين المألوفة لفحص الصفحة وإزالة الأخطاء وتعديلها كما تفعل عادةً. إذا كنت تستخدم Headless آليًا، هذه الصفحة هي أيضًا أداة فعّالة لتصحيح الأخطاء من خلال الاطّلاع على كل طلبات بروتوكول DevTools الخام التي يتم إرسالها عبر الإنترنت للتواصل مع المتصفّح.
استخدام (عقدة) آليًا
محرك العرائس
Puppeteer هي مكتبة Node طوَّرها فريق Chrome. وتوفّر واجهة برمجة تطبيقات عالية المستوى للتحكّم في Chrome (أو الكامل) بدون واجهة مستخدم. وهي مشابهة لغيرها من مكتبات الاختبار المبرمَج، مثل Phantom وNightmareJS، ولكنها لا تعمل إلا مع أحدث إصدارات Chrome.
من بين أمور أخرى، يمكن استخدام Puppeteer لالتقاط لقطات شاشة بسهولة وإنشاء ملفات PDF والتنقّل في الصفحات واسترداد معلومات عن هذه الصفحات. أنصح باستخدام المكتبة إذا كنت تريد أتمتة اختبار المتصفّح بسرعة. ويزيل هذا الإصدار تعقيدات بروتوكول DevTools ويتولى المهام المتكررة، مثل إطلاق مثيل 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. ننصحك باستخدام هذا الإجراء إذا كنت تريد استخدام بروتوكول DevTools مباشرةً.
تشغيل Chrome
لا يبدأ chrome-remote-interface متصفّح 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، وتم استخراجها الآن لاستخدامها بشكل مستقل.
ستعثر chrome-launcher
وحدة NPM
على مكان تثبيت Chrome، وستُعدّ مثيل تصحيح أخطاء، وستشغّل المتصفّح، وستغلقه
عند انتهاء البرنامج. والأفضل من ذلك أنّه يعمل على جميع المنصّات بفضل
Node.
سيحاول 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
في الوقت الحالي، يفتح Selenium نسخة كاملة من Chrome. بعبارة أخرى، هو حلّ مبرمَج ولكنّه ليس مبرمَجًا بالكامل. ومع ذلك، يمكن ضبط Selenium لتشغيل Chrome بدون واجهة مستخدم رسومية بعدة خطوات بسيطة. ننصحك باستخدام تشغيل Selenium مع Headless Chrome إذا كنت تريد الحصول على تعليمات كاملة حول كيفية إعداد العناصر بنفسك، ولكننا أضفنا بعض المثال أدناه لمساعدتك في البدء.
استخدام ChromeDriver
يستخدم الإصدار 2.32 من ChromeDriver 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-مشغّل التطبيقات - وحدة عقدة لتشغيل Chrome، جاهزة للتشغيل الآلي
إصدارات تجريبية
- "الويب بلا واجهة مستخدم رسومية": مشاركة مدونة رائعة نشرها "بول كينلان" حول استخدام ميزة "بلا واجهة مستخدم رسومية" مع api.ai.
الأسئلة الشائعة
هل أحتاج إلى علامة --disable-gpu
؟
على نظام التشغيل Windows فقط ولم تعُد الأنظمة الأساسية الأخرى تتطلّب ذلك. يتم حلّ بعض الأخطاء مؤقتًا في العلامة --disable-gpu
. ولن تحتاج إلى هذا الخيار في الإصدارات المستقبلية من Chrome. يُرجى الاطّلاع على crbug.com/737678
لمزيد من المعلومات.
هل ما زلت بحاجة إلى Xvfb؟
لا، لأنّ Chrome بلا واجهة مستخدم رسومية لا يستخدم نافذة، وبالتالي لم تعُد هناك حاجة إلى خادم عرض، مثل Xvfb. يمكنك إجراء اختباراتك الآلية بدونها.
ما هو Xvfb؟ Xvfb هو خادم شاشة في الذاكرة للأنظمة المشابهة لنظام التشغيل Unix، ويتيح لك تشغيل التطبيقات الرسومية (مثل Chrome) بدون شاشة خارجية مرفقة. يستخدم العديد من المستخدمين Xvfb لتشغيل إصدارات سابقة من Chrome لإجراء اختبار "بلا واجهة مستخدم رسومية".
كيف يمكنني إنشاء حاوية Docker تشغّل Chrome بلا واجهة مستخدم رسومية؟
اطّلِع على lighthouse-ci. يتضمّن المثال
ملف Dockerfile
الذي يستخدم node:8-slim
كصورة أساسية، ويُثبّت +
يشغّل Lighthouse
على App Engine Flex.
هل يمكنني استخدام هذا مع Selenium / WebDriver / ChromeDriver؟
نعم. راجِع مقالة استخدام Selenium وWebDriver وChromeDriver.
ما هي علاقة ذلك ببرنامج PhantomJS؟
يشبه Chrome بدون واجهة مستخدم أدوات مثل PhantomJS. ويمكن استخدام كلاهما للاختبار الآلي في بيئة بدون شاشة. يتمثل الاختلاف الرئيسي بينهما في أنّ Phantom يستخدم إصدارًا قديمًا من WebKit كمحرّك عرض، في حين يستخدم Headless Chrome أحدث إصدار من Blink.
في الوقت الحالي، يقدّم Phantom أيضًا واجهة برمجة تطبيقات ذات مستوى أعلى من بروتوكول أدوات المطوّرين.
أين يمكنني الإبلاغ عن الأخطاء؟
بالنسبة إلى الأخطاء في "Chrome بلا واجهة مستخدم رسومية"، يُرجى الإبلاغ عنها على crbug.com.
بالنسبة إلى الأخطاء في بروتوكول أدوات مطوّري البرامج، يُرجى تقديمها على github.com/ChromeDevTools/devtools-protocol.