Можно ли запустить Chrome / Chromium без головы в облачной функции Google?

Есть ли способ запустить Headless Chrome / Chromium в Google Облачная функция? Я понимаю, что могу включать и запускать статически скомпилированные двоичные файлы в GCF. Могу ли я получить статически скомпилированную версию Chrome, которая подойдет для этого?


person at.    schedule 02.05.2017    source источник
comment
Некоторые работают над этим github.com/adieuadieu/serverless-chrome   -  person Palani    schedule 11.05.2017


Ответы (4)


Среда выполнения Node.js 8 для Google Cloud Functions теперь включает все необходимые пакеты ОС для запуска Headless Chrome.

Вот пример кода функции 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"
  }
}
person Steren    schedule 01.08.2018
comment
будет ли puppeteer зависимостью, которая кэшируется Google, поэтому она оптимизирована, или это что-то, что потребует больше ресурсов (например, памяти, процессора) для использования - person jasan; 08.08.2018
comment
функция не развертывается в моей учетной записи firebase. Другие (не асинхронные) делают. У меня включен npm 8 - person daniel; 13.08.2018
comment
Есть ли шанс получить поддержку среды выполнения Java, чтобы она могла работать с Selenium? - person kashiB; 09.09.2018
comment
@ebidel, есть ли в среде Python эквивалентные пакеты для запуска Chrome без головы? - person FKrauss; 26.03.2019

Я только что развернул функцию GCF, запускающую безголовый Chrome. Пара замечаний:

  1. вам нужно статически скомпилировать Chromium и NSS на Debian 8
  2. перед запуском Chromium вам необходимо исправить переменные среды, чтобы они указывали на NSS.
  3. производительность намного хуже, чем у AWS Lambda (3+ секунды)

Во-первых, вы сможете найти множество инструкций в Интернете.

Для 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

Надеюсь, это поможет.

person Alix Axel    schedule 27.03.2018

Как упоминалось в комментарии, ведется работа над возможным решением для запуска автономного браузера в облачной функции. Обсуждение прямого действия: "безголовый хром & aws lambda "можно прочитать в группах Google.

person George    schedule 31.05.2017

Вопрос по адресу. Было ли вы можете запускать безголовый хром или хром в Firebase Cloud Functions ... ответ - НЕТ! поскольку проект node.js не будет иметь доступа к исполняемым файлам chrome / chromium и, следовательно, потерпит неудачу! (ДОВЕРЬТЕ МНЕ - я пробовал!).

Лучшее решение - использовать пакет Phantom npm, который использует PhantomJS под капотом: https://www.npmjs.com/package/phantom

Документы и информацию можно найти здесь:

http://amirraminfar.com/phantomjs-node/#/

or

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') и запустив текстовый поиск или регулярное выражение, чтобы увидеть, есть ли на вашей странице закончил загрузку.

Я создал универсальную асинхронную функцию, возвращающую содержимое страницы (в виде строки) в случае успеха и генерирующую исключение в случае сбоя или тайм-аута. В качестве параметров он принимает переменные для страницы, текст (строка для поиска, указывающая на успех), ошибка (строка, указывающая на сбой, или 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);
    }

Удачного ползания!

person Sagar Patel    schedule 13.08.2018