node.js - 如何使用 puppeteer 获取下载流(缓冲区)?
问题描述
我想获取下载内容(缓冲区),然后很快将数据存储在我的 S3 帐户中。到目前为止,我无法找到一些解决方案......在网上寻找一些例子,我注意到有很多人有这个问题。根据以下代码段,我尝试(未成功)使用 page.on("response") 事件来检索原始响应内容:
const bucket = [];
await page.on("response", async response => {
const url = response.url();
if (
url ===
"https://the.earth.li/~sgtatham/putty/0.71/w32/putty-0.71-installer.msi"
) {
try {
if (response.status() === 200) {
bucket.push(await response.buffer());
console.log(bucket);
// I got the following: 'Protocol error (Network.getResponseBody): No resource with given identifier found' }
}
} catch (err) {
console.error(err, "ERROR");
}
}
});
使用上面的代码,我打算检测下载对话框的事件,然后以某种方式接收二进制内容。
我不确定这是否是正确的方法。我注意到有些人使用基于读取文件的解决方案,换句话说,下载完成后,他们从磁盘读取存储的文件。有类似的讨论:https ://github.com/GoogleChrome/puppeteer/issues/299 。
我的问题是:有什么方法(使用 puppeteer)来拦截下载流,而不必先将文件保存到磁盘?
非常感谢。
解决方案
问题是,一旦发生任何类型的导航请求,缓冲区就会被清除。在您的情况下,这可能是重定向或页面重新加载。
要解决这个问题,您需要确保只要您的资源还没有完成下载,页面就不会发出任何导航请求。为此,我们可以使用page.setRequestInterception
.
有一个简单的解决方案可以帮助您入门,但可能并不总是有效,还有一个更复杂的解决方案可以解决这个问题。
简单的解决方案
此解决方案在初始请求后取消任何导航请求。这意味着,页面上的任何重新加载或导航都将不起作用。因此,资源的缓冲区不会被清除。
const browser = await puppeteer.launch();
const [page] = await browser.pages();
let initialRequest = true;
await page.setRequestInterception(true);
page.on('request', request => {
// cancel any navigation requests after the initial page.goto
if (request.isNavigationRequest() && !initialRequest) {
return request.abort();
}
initialRequest = false;
request.continue();
});
page.on('response', async (response) => {
if (response.url() === 'RESOURCE YOU WANT TO DOWNLOAD') {
const buffer = await response.buffer();
// handle buffer
}
});
await page.goto('...');
先进的解决方案
以下代码将一个接一个地处理每个请求。如果您下载缓冲区,它将等到缓冲区下载完成后再处理下一个请求。
const browser = await puppeteer.launch();
const [page] = await browser.pages();
let paused = false;
let pausedRequests = [];
const nextRequest = () => { // continue the next request or "unpause"
if (pausedRequests.length === 0) {
paused = false;
} else {
// continue first request in "queue"
(pausedRequests.shift())(); // calls the request.continue function
}
};
await page.setRequestInterception(true);
page.on('request', request => {
if (paused) {
pausedRequests.push(() => request.continue());
} else {
paused = true; // pause, as we are processing a request now
request.continue();
}
});
page.on('requestfinished', async (request) => {
const response = await request.response();
if (response.url() === 'RESOURCE YOU WANT TO DOWNLOAD') {
const buffer = await response.buffer();
// handle buffer
}
nextRequest(); // continue with next request
});
page.on('requestfailed', nextRequest);
await page.goto('...');
推荐阅读
- python - 如何显示特定产品的所有评论?
- python - 使用别名运行的 Python
- python - 如何使用 python 在 google colab 中保存 json 转储?
- angular - 在角度 6 中,如何使用 '-' 而不是使用 '/' 来制作 url
- wordpress - 云上的多区域 wordpress 部署
- python - Matplotlib 实时图能够处理数据更新之间的长时间
- r - 应用函数中二元运算符的非数字参数
- java - 获取 java.lang.NoClassDefFoundError: 无法初始化类 com.sun.org.apache.xml.internal.serializer.Encodings
- java - 在 Eclipse IDE 中执行 Flink 应用程序
- javascript - 使用另一个状态变量计算一个状态变量