使用 Puppeteer 加载动态网页适用于本地主机,但不适用于 Heroku
Loading dynamic webpage with Puppeteer works on localhost but not Heroku
Node.js 带有 Express 的应用程序,部署在 Heroku 上。它只是动态网页。加载静态网页工作正常。
加载动态网页在本地主机上有效,但在 Heroku 上它会抛出 code=H12
、desc="Request timeout"
、service=30000ms
、status=503
.
此外,在执行 heroku restart
或部署后,似乎总是有一个 status=200
实例只加载动态网页的静态部分。
日志截图here。
我尝试了以下方法,当部署在 Heroku 上(例如 Error R14 (Memory quota exceeded)
和 code=H13 desc="Connection closed without response"
)时,它们都导致了相同或其他意外结果:
- 切换我使用的 Puppeteer Heroku buildpack。我试过 this troubleshooting guide and this comment.
中提到的那些
- 在 Puppeteer 的
launch
参数中添加 headless: true
。
- 在 Puppeteer 的
launch
参数的 args
中添加 --no-sandbox
、--disable-setuid-sandbox
、--single-process
和 --no-zygote
标志。 (参考:this comment & this comment)
- 将 Puppeteer 的
goto
函数中的 waitUntil
参数设置为 domcontentloaded
、networkidle0
和 networkidle2
。 (参考:this comment)
- 在 Puppeteer
goto
函数中传递一个 timeout
参数;我已经具体尝试了 30000
和 60000
,以及每个 this comment. 0
- 使用
waitForSelector
函数。
- 正在清除 Heroku 的构建缓存,根据 this article。
- 在控制台打印
url
变量(见下面我的代码)。输出符合预期。
我观察到:
- 使用我现在的代码(见下文),
try-catch-finally
块永远不会捕获任何错误。它始终是以下情况之一:我得到不完整的结果(请求的动态网页的静态部分),或 应用程序崩溃 (code=H13 desc="Connection closed without response"
)。因此,我无法从 catch
块中尝试在控制台中打印 exception
得到任何结果。
关于如何让它工作的任何想法?
const app = express();
const puppeteer = require("puppeteer");
let port = process.env.PORT || 3000;
let browser;
...
app.listen(port, async() => {
browser = await puppeteer
.launch({
timeout: 0,
headless: true,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--single-process",
"--no-zygote",
],
});
});
...
app.get("/appropriate-route-name", async (req, res) => {
let url = req.query.url;
let page = await browser.newPage();
try {
await page.goto(url, {
waitUntil: "networkidle2",
});
res.send({ data: await page.content() });
} catch (exception) {
res.send({ data: null });
} finally {
await browser.close();
}
}
能够通过使用 user-agents
使其正常工作。动态页面现在可以在 Heroku 上正常加载;请求不再每次都超时。
const app = express();
const puppeteer = require("puppeteer");
let port = process.env.PORT || 3000;
var userAgent = require("user-agents");
...
app.get("/route-name", async (req, res) => {
let url = req.query.url;
let browser = await puppeteer.launch({
args: ["--no-sandbox"],
});
let page = await browser.newPage();
try {
await page.setUserAgent(userAgent.toString()); // added this
await page.goto(url, {
timeout: 30000,
waitUntil: "newtorkidle2", // or "networkidle0", depending on what you need
});
res.send({ data: await page.content() });
} catch (e) {
res.send({ data: null });
} finally {
await browser.close();
}
});
Node.js 带有 Express 的应用程序,部署在 Heroku 上。它只是动态网页。加载静态网页工作正常。
加载动态网页在本地主机上有效,但在 Heroku 上它会抛出 code=H12
、desc="Request timeout"
、service=30000ms
、status=503
.
此外,在执行 heroku restart
或部署后,似乎总是有一个 status=200
实例只加载动态网页的静态部分。
日志截图here。
我尝试了以下方法,当部署在 Heroku 上(例如 Error R14 (Memory quota exceeded)
和 code=H13 desc="Connection closed without response"
)时,它们都导致了相同或其他意外结果:
- 切换我使用的 Puppeteer Heroku buildpack。我试过 this troubleshooting guide and this comment. 中提到的那些
- 在 Puppeteer 的
launch
参数中添加headless: true
。 - 在 Puppeteer 的
launch
参数的args
中添加--no-sandbox
、--disable-setuid-sandbox
、--single-process
和--no-zygote
标志。 (参考:this comment & this comment) - 将 Puppeteer 的
goto
函数中的waitUntil
参数设置为domcontentloaded
、networkidle0
和networkidle2
。 (参考:this comment) - 在 Puppeteer
goto
函数中传递一个timeout
参数;我已经具体尝试了30000
和60000
,以及每个 this comment. - 使用
waitForSelector
函数。 - 正在清除 Heroku 的构建缓存,根据 this article。
- 在控制台打印
url
变量(见下面我的代码)。输出符合预期。
0
我观察到:
- 使用我现在的代码(见下文),
try-catch-finally
块永远不会捕获任何错误。它始终是以下情况之一:我得到不完整的结果(请求的动态网页的静态部分),或 应用程序崩溃 (code=H13 desc="Connection closed without response"
)。因此,我无法从catch
块中尝试在控制台中打印exception
得到任何结果。
关于如何让它工作的任何想法?
const app = express();
const puppeteer = require("puppeteer");
let port = process.env.PORT || 3000;
let browser;
...
app.listen(port, async() => {
browser = await puppeteer
.launch({
timeout: 0,
headless: true,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--single-process",
"--no-zygote",
],
});
});
...
app.get("/appropriate-route-name", async (req, res) => {
let url = req.query.url;
let page = await browser.newPage();
try {
await page.goto(url, {
waitUntil: "networkidle2",
});
res.send({ data: await page.content() });
} catch (exception) {
res.send({ data: null });
} finally {
await browser.close();
}
}
能够通过使用 user-agents
使其正常工作。动态页面现在可以在 Heroku 上正常加载;请求不再每次都超时。
const app = express();
const puppeteer = require("puppeteer");
let port = process.env.PORT || 3000;
var userAgent = require("user-agents");
...
app.get("/route-name", async (req, res) => {
let url = req.query.url;
let browser = await puppeteer.launch({
args: ["--no-sandbox"],
});
let page = await browser.newPage();
try {
await page.setUserAgent(userAgent.toString()); // added this
await page.goto(url, {
timeout: 30000,
waitUntil: "newtorkidle2", // or "networkidle0", depending on what you need
});
res.send({ data: await page.content() });
} catch (e) {
res.send({ data: null });
} finally {
await browser.close();
}
});