Есть ли способ запустить Headless Chrome/Chromium в облачной функции Google? Я понимаю, что могу включить и запустить статически скомпилированные двоичные файлы в GCF. Могу ли я получить статически скомпилированную версию Chrome, которая будет работать для этого?
Можно ли использовать Chrome Head Chrome/Chromium в облачной функции Google?
Ответ 1
Время выполнения Node.js 8 для облачных функций Google теперь включает в себя все необходимые пакеты ОС для запуска Chrome Headless.
Вот пример кода функции HTTP, которая возвращает скриншоты:
Основной файл index.js
:
const puppeteer = require('puppeteer');
exports.screenshot = async (req, res) => {
const url = req.query.url;
if (!url) {
return res.send('Please provide URL as GET parameter, for example: <a href="?url=https://example.com">?url=https://example.com</a>');
}
const browser = await puppeteer.launch({
args: ['--no-sandbox']
});
const page = await browser.newPage();
await page.goto(url);
const imageBuffer = await page.screenshot();
await browser.close();
res.set('Content-Type', 'image/png');
res.send(imageBuffer);
}
и package.json
{
"name": "screenshot",
"version": "0.0.1",
"dependencies": {
"puppeteer": "^1.6.2"
}
}
Ответ 2
Я только что развернул функцию GCF с безголовым Chrome. Несколько приемов:
- вам нужно статически компилировать Chromium и NSS на Debian 8
- вам нужно исправить переменные окружения, чтобы указать на NSS перед запуском Chromium
- производительность намного хуже, чем то, что вы получите на AWS Lambda (3+ секунды)
Для 1 вы можете найти множество инструкций в Интернете.
Для 2 код, который я использую, следующий:
static executablePath() {
let bin = path.join(__dirname, '..', 'bin', 'chromium');
let nss = path.join(__dirname, '..', 'bin', 'nss', 'Linux3.16_x86_64_cc_glibc_PTH_64_OPT.OBJ');
if (process.env.PATH === undefined) {
process.env.PATH = path.join(nss, 'bin');
} else if (process.env.PATH.indexOf(nss) === -1) {
process.env.PATH = [path.join(nss, 'bin'), process.env.PATH].join(':');
}
if (process.env.LD_LIBRARY_PATH === undefined) {
process.env.LD_LIBRARY_PATH = path.join(nss, 'lib');
} else if (process.env.LD_LIBRARY_PATH.indexOf(nss) === -1) {
process.env.LD_LIBRARY_PATH = [path.join(nss, 'lib'), process.env.LD_LIBRARY_PATH].join(':');
}
if (fs.existsSync('/tmp/chromium') === true) {
return '/tmp/chromium';
}
return new Promise(
(resolve, reject) => {
try {
fs.chmod(bin, '0755', () => {
fs.symlinkSync(bin, '/tmp/chromium'); return resolve('/tmp/chromium');
});
} catch (error) {
return reject(error);
}
}
);
}
При запуске Chrome вам также необходимо использовать несколько необходимых аргументов, а именно:
--disable-dev-shm-usage
--disable-setuid-sandbox
--no-first-run
--no-sandbox
--no-zygote
--single-process
Надеюсь, это поможет.
Ответ 3
Как упоминалось в комментарии, ведется работа над возможным решением для запуска браузера без браузера в облачной функции. Прямо применимое обсуждение: " безгласный хром и aws лямбда" можно прочитать в группах Google.
Ответ 4
Вопрос в. был ли у вас безголовый хром или хром в облачных функциях Firebase... ответ НЕТ! так как проект node.js не будет иметь доступ к исполняемым файлам chrome/chromium и, следовательно, не сработает! (ДОВЕРИЕ МЕНЯ - Я ПРОШЕЛ!).
Лучшим решением является использование пакета Phantom npm, который использует PhantomJS под капотом: https://www.npmjs.com/package/phantom
Документы и информация можно найти здесь:
http://amirraminfar.com/phantomjs-node/#/
или же
https://github.com/amir20/phantomjs-node
На сайте, на котором я пытался просканировать, было реализовано программное обеспечение для очистки экрана, трюк заключается в том, чтобы дождаться загрузки страницы путем поиска ожидаемой строки или соответствия регулярному выражению, то есть я делаю регулярное выражение для a, если вам нужно регулярное выражение любой сложности для вас - свяжитесь с https://AppLogics.uk/ - начиная с 5 фунтов стерлингов (GPB).
здесь приведен фрагмент машинописного текста для вызова http или https:
const phantom = require('phantom');
const instance: any = await phantom.create(['--ignore-ssl-errors=yes', '--load-images=no']);
const page: any = await instance.createPage();
const status = await page.open('https://somewebsite.co.uk/');
const content = await page.property('content');
опять же в JavaScript:
const phantom = require('phantom');
const instance = yield phantom.create(['--ignore-ssl-errors=yes', '--load-images=no']);
const page = yield instance.createPage();
const status = yield page.open('https://somewebsite.co.uk/');
const content = yield page.property('content');
Это легкий бит! если его статическая страница в значительной степени выполнена, и вы можете анализировать HTML-код в виде пакета cheerio npm: https://github.com/cheeriojs/cheerio - реализация ядра JQuery, предназначенного для серверов!
Однако, если это страница с динамической загрузкой, то есть ленивая загрузка или даже методы скремблирования, вам нужно будет дождаться обновления страницы путем циклирования и вызова page.property('content')
и запуска текстового поиска или regex, чтобы узнать, закончилась ли ваша страница.
Я создал общую асинхронную функцию, возвращающую содержимое страницы (как строку) при успешном запуске и выдает исключение при сбое или таймауте. В качестве параметров в качестве параметров используются переменные для страницы, текст (строка для поиска, указывающая на успех), ошибка (строка для указания отказа или null, чтобы не проверять наличие ошибки), и тайм-аут (номер - сам по себе):
Машинопись:
async function waitForPageToLoadStr(page: any, text: string, error: string, timeout: number): Promise<string> {
const maxTime = timeout ? (new Date()).getTime() + timeout : null;
let html: string = '';
html = await page.property('content');
async function loop(): Promise<string>{
async function checkSuccess(): Promise <boolean> {
html = await page.property('content');
if (!isNullOrUndefined(error) && html.includes(error)) {
throw new Error('Error string found: ${ error }');
}
if (maxTime && (new Date()).getTime() >= maxTime) {
throw new Error('Timed out waiting for string: ${ text }');
}
return html.includes(text)
}
if (await checkSuccess()){
return html;
} else {
return loop();
}
}
return await loop();
}
JavaScript:
function waitForPageToLoadStr(page, text, error, timeout) {
return __awaiter(this, void 0, void 0, function* () {
const maxTime = timeout ? (new Date()).getTime() + timeout : null;
let html = '';
html = yield page.property('content');
function loop() {
return __awaiter(this, void 0, void 0, function* () {
function checkSuccess() {
return __awaiter(this, void 0, void 0, function* () {
html = yield page.property('content');
if (!isNullOrUndefined(error) && html.includes(error)) {
throw new Error('Error string found: ${error}');
}
if (maxTime && (new Date()).getTime() >= maxTime) {
throw new Error('Timed out waiting for string: ${text}');
}
return html.includes(text);
});
}
if (yield checkSuccess()) {
return html;
}
else {
return loop();
}
});
}
return yield loop();
});
}
Я лично использовал эту функцию следующим образом:
Машинопись:
try {
const phantom = require('phantom');
const instance: any = await phantom.create(['--ignore-ssl-errors=yes', '--load-images=no']);
const page: any = await instance.createPage();
const status = await page.open('https://somewebsite.co.uk/');
await waitForPageToLoadStr(page, '<div>Welcome to somewebsite</div>', '<h1>Website under maintenance, try again later</h1>', 1000);
} catch (error) {
console.error(error);
}
JavaScript:
try {
const phantom = require('phantom');
const instance = yield phantom.create(['--ignore-ssl-errors=yes', '--load-images=no']);
const page = yield instance.createPage();
yield page.open('https://vehicleenquiry.service.gov.uk/');
yield waitForPageToLoadStr(page, '<div>Welcome to somewebsite</div>', '<h1>Website under maintenance, try again later</h1>', 1000);
} catch (error) {
console.error(error);
}
Счастливый ползающий!