Javascript 木偶演员不';不要关闭浏览器

Javascript 木偶演员不';不要关闭浏览器,javascript,express,async-await,puppeteer,Javascript,Express,Async Await,Puppeteer,我在express/node/ubuntu上运行Puppeter,如下所示: var puppeteer = require('puppeteer'); var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { (async () => { headless = tr

我在express/node/ubuntu上运行Puppeter,如下所示:

var puppeteer = require('puppeteer');
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
    (async () => {
        headless = true;
        const browser = await puppeteer.launch({headless: true, args:['--no-sandbox']});
        const page = await browser.newPage();
        url = req.query.url;
        await page.goto(url);
        let bodyHTML = await page.evaluate(() => document.body.innerHTML);
        res.send(bodyHTML)
        await browser.close();
    })();
});
多次运行此脚本会留下数百个僵尸:

$ pgrep chrome | wc -l
133
这会阻塞srv

我该如何解决这个问题

从Express JS脚本运行
kill
可以解决这个问题吗

除了《木偶演员》和《无头铬合金》之外,还有更好的方法获得同样的效果吗

我用


像这样用try-catch包装您的代码,看看是否有帮助

headless = true;
const browser = await puppeteer.launch({headless: true, args:['--no-sandbox']});
try {
  const page = await browser.newPage();
  url = req.query.url;
  await page.goto(url);
  let bodyHTML = await page.evaluate(() => document.body.innerHTML);
  res.send(bodyHTML);
  await browser.close();
} catch (error) {
  console.log(error);
  await browser.close();
} finally {
  await browser.close();
}

在发送响应之前,请尝试关闭浏览器

var puppeteer = require('puppeteer');
var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
    (async () => {
        headless = true;
        const browser = await puppeteer.launch({headless: true});
        const page = await browser.newPage();
        url = req.query.url;
        await page.goto(url);
        let bodyHTML = await page.evaluate(() => document.body.innerHTML);
        await browser.close();
        res.send(bodyHTML);
    })();
});

啊!这是一个简单的疏忽。如果出现错误,并且您的
等待browser.close()
从未执行,从而留下僵尸,该怎么办

使用
shell.js
似乎是解决这个问题的一种黑客方法

更好的做法是使用
try..catch..finally
。原因是您希望关闭浏览器,而不管是否有愉快的流或抛出错误。 与其他代码片段不同,您不必在
catch
块和
finally
块中尝试关闭浏览器<无论是否抛出错误,始终执行代码>最终块

因此,您的代码应该如下所示:

const puppeteer = require('puppeteer');
const express = require('express');

const router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  (async () => {
    try {
      headless = true;
      const browser = await puppeteer.launch({
        headless: true,
        args: ['--no-sandbox'],
      });
      const page = await browser.newPage();
      url = req.query.url;
      await page.goto(url);
      const bodyHTML = await page.evaluate(() => document.body.innerHTML);
      res.send(bodyHTML);
    } catch (e) {
      console.log(e);
    } finally {
      await browser.close();
    }
  })();
});


希望这有帮助

我遇到了同样的问题,虽然您的shelljs解决方案确实有效,但它会杀死所有chrome进程,这可能会中断仍在处理请求的进程。这里有一个更好的解决方案,应该是可行的

var puppeteer = require('puppeteer');
var express = require('express');
var router = express.Router();

router.get('/', function (req, res, next) {
    (async () => {
        await puppeteer.launch({ headless: true }).then(async browser => {
            const page = await browser.newPage();
            url = req.query.url;
            await page.goto(url);
            let bodyHTML = await page.evaluate(() => document.body.innerHTML);
            await browser.close();
            res.send(bodyHTML);
        });
    })();
});

根据我的经验,在调用close之后,浏览器关闭过程可能需要一些时间。无论如何,您可以检查browser process属性以检查它是否仍然未关闭,并强制终止它

if (browser && browser.process() != null) browser.process().kill('SIGINT');
我还在下面发布我的木偶资源经理的完整代码。看看
bw.on('disconnected',async()=>{

const puppeter=require('puppeter-extra'))
const randomUseragent=require('random-useragent');
const StealthPlugin=require('puppeter-extra-plugin-steavy')
const USER_AGENT='Mozilla/5.0(麦金塔;英特尔Mac OS X 10_14_1)AppleWebKit/537.36(KHTML,像Gecko)Chrome/73.0.3683.75 Safari/537.36';
木偶演员。使用(StealthPlugin())
功能资源管理器(loadImages){
让browser=null;
常数this=这个;
设重试次数=0;
让isReleased=false;
this.init=async()=>{
isReleased=false;
重试次数=0;
browser=等待runBrowser();
};
this.release=async()=>{
isReleased=真;
if(browser)等待browser.close();
}
this.createPage=异步(url)=>{
如果(!browser)browser=等待runBrowser();
返回等待创建页面(浏览器、url);
}
异步函数runBrowser(){
const bw=wait puppeter.launch({
无头:是的,
devtools:false,
ignoreHTTPSErrors:是的,
slowMo:0,
参数:['--disable gpu','--no sandbox','--no zygote','--disable setuid sandbox','--disable-accelerated-2d-canvas','--disable dev shm usage',“--proxy server='direct://',“--proxy pass list=*”]
});
on('disconnected',async()=>{
如果(被删除)返回;
console.log(“浏览器崩溃”);
如果(重试){
如果(req.resourceType()='stylesheet'| | req.resourceType()=='font'| | req.resourceType()=='image'){
请求中止();
}否则{
请求继续();
}
});
}
等待页面。评估onnewdocument(()=>{
//通过webdriver检查
Object.defineProperty(导航器,“webdriver”{
get:()=>false,
});
});
等待页面。评估onnewdocument(()=>{
//通过镀铬检查
window.chrome={
运行时:{},
//等等。
};
});
等待页面。评估onnewdocument(()=>{
//通过插件检查
const originalQuery=window.navigator.permissions.query;
return window.navigator.permissions.query=(参数)=>(
parameters.name==“通知”?
Promise.resolve({state:Notification.permission}):
原始查询(参数)
);
});
等待页面。评估onnewdocument(()=>{
//覆盖'plugins'属性以使用自定义getter。
Object.defineProperty(导航器,'插件'{
//对于当前测试,它只需要'length>0',
//但如果必要的话,我们也可以模仿插件。
获取:()=>[1,2,3,4,5],
});
});
等待页面。评估onnewdocument(()=>{
//覆盖'plugins'属性以使用自定义getter。
Object.defineProperty(导航器,'语言'{
获取:()=>['en-US','en'],
});
});
wait page.goto(url,{waitUntil:'networkidle2',超时:0});
返回页面;
}
}
module.exports={ResourceManager}

我使用以下基本设置来运行木偶演员:

const puppeter=require(“木偶演员”);
让浏览器;
(异步()=>{
browser=wait puppeter.launch();
const[page]=wait browser.pages();
/*使用页面*/
})()
.catch(err=>console.error(err))
.finally(异步()=>等待browser.close())
;
在这里,
finally
块保证浏览器将正确关闭,无论是否抛出错误。错误会被记录(如果需要)。我喜欢
.catch
。finally
作为链接调用,因为主线木偶程序代码更平坦一层,但这实现了同样的功能:

const puppeter=require(“木偶演员”);
(异步()=>{
让浏览器;
试一试{
browser=wait puppeter.launch();
const[page]=wait browser.pages();
/*使用页面*/
}
捕捉(错误){
if (browser && browser.process() != null) browser.process().kill('SIGINT');