使用 node/puppeteer/js 从直接下载 link 下载 pdf 文件
Downloading pdf files from direct download link using node/puppeteer/js
我需要从直接下载中下载大约 300 个文件 link。当直接在浏览器中打开 link 时,会触发自动 pdf 下载。该文件已下载,浏览器不会去任何地方。 link如下:
www.link.com/store/item/123
在link中,每次循环都会更改123部分。
我正在考虑使用 puppeteer(带 goto),但我想由于访问 link 会自动触发 pdf 的下载并且实际上并没有转到该页面,所以它失败了。
这是我尝试过的方法,但根本不起作用:
const links = ['123', '456'];
(async () => {
const browser = await puppeteer.launch({
headless: false //preferably would run with true
});
links.forEach( async link => {
const page = await browser.newPage();
await page.goto(
linkBeginning + link
);
await browser.close();
})
})();
我四处搜索,但我真的找不到这个具体案例,所有其他案例都更侧重于用户端或者在实际 link 中有目标文件(比如 xx/store/doc。 PDF)。不太确定这是否有所作为。我只需要一个脚本,可以一次性获取 pdf 文件 运行.
如果有人在 php/python 中有解决方案也可以,因为这只是一次性的事情。
编辑:
最终在 html
完成
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="sku.js"></script>
<script>
const linkStart = 'https://www.sols-europe.com/gb/pdfpublication/pdf/product/sku/';
sku.forEach(element => {
document.write('<a target = "_blank" class="click" href="' + linkStart + element.id +'">'+ element.id +'</a></br>')
});
</script>
</head>
<body></body>
</html>
<script>
const clickInterval = setInterval(function () {
const el = document.querySelector('.click:not(.clicked)');
if(el){
el.classList.add('clicked');
el.click()
} else {
clearInterval(clickInterval);
}
}, 2000);
</script>
您将 browser.close() 放在循环内不是一件好事。
所以我把它移到 forEach 外面,改为 page.close()。
const links = ['123', '456']
const linkBeginning = 'https://www.link.com/store/item/'
;(async () => {
const browser = await puppeteer.launch({
headless: false //preferably would run with true
})
links.forEach( async link => {
const page = await browser.newPage()
const session = await page.target().createCDPSession()
await session.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath: './pdf/'
})
await page.goto(linkBeginning + link)
await page.close() // Don't use browser.close() inside loop
})
await browser.close() // Use here instead
})()
您不需要 puppeteer 来执行此操作,并且您可以在 NodeJS 中相当轻松地实现它:
import http from "https";
import fs from "fs";
(async () => {
const skus = ["00548", "03575"];
const filesPromiseArray = skus.map(
(sku) =>
new Promise((resolve, reject) => {
const file = fs.createWriteStream(`${sku}.pdf`);
const request = http.get(`https://www.sols-europe.com/gb/pdfpublication/pdf/product/sku/${sku}`, (response) =>
response.pipe(file)
);
file.on("finish", resolve);
file.on("error", reject);
})
);
try {
await Promise.all(filesPromiseArray);
} catch {
console.log("There was an error downloading one of the files");
}
})();
这段代码在做什么?
- 使用您的
skus
数组,我们正在使用 .map()
将它们转换为请求数组。
- 在
.map()
中,我们正在创建一个 Promise
,它将在文件完成下载时成功 (resolve
),如果下载错误。
- 然后我们
await
我们刚刚创建的所有请求。如果其中之一失败,它将记录。
注:
如果您使用的是 CommonJS(package.json
中的 "type":"commonjs",
),请将两个导入替换为:
const http = require('https');
const fs = require('fs');
我需要从直接下载中下载大约 300 个文件 link。当直接在浏览器中打开 link 时,会触发自动 pdf 下载。该文件已下载,浏览器不会去任何地方。 link如下:
www.link.com/store/item/123
在link中,每次循环都会更改123部分。
我正在考虑使用 puppeteer(带 goto),但我想由于访问 link 会自动触发 pdf 的下载并且实际上并没有转到该页面,所以它失败了。
这是我尝试过的方法,但根本不起作用:
const links = ['123', '456'];
(async () => {
const browser = await puppeteer.launch({
headless: false //preferably would run with true
});
links.forEach( async link => {
const page = await browser.newPage();
await page.goto(
linkBeginning + link
);
await browser.close();
})
})();
我四处搜索,但我真的找不到这个具体案例,所有其他案例都更侧重于用户端或者在实际 link 中有目标文件(比如 xx/store/doc。 PDF)。不太确定这是否有所作为。我只需要一个脚本,可以一次性获取 pdf 文件 运行.
如果有人在 php/python 中有解决方案也可以,因为这只是一次性的事情。
编辑: 最终在 html
完成<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="sku.js"></script>
<script>
const linkStart = 'https://www.sols-europe.com/gb/pdfpublication/pdf/product/sku/';
sku.forEach(element => {
document.write('<a target = "_blank" class="click" href="' + linkStart + element.id +'">'+ element.id +'</a></br>')
});
</script>
</head>
<body></body>
</html>
<script>
const clickInterval = setInterval(function () {
const el = document.querySelector('.click:not(.clicked)');
if(el){
el.classList.add('clicked');
el.click()
} else {
clearInterval(clickInterval);
}
}, 2000);
</script>
您将 browser.close() 放在循环内不是一件好事。
所以我把它移到 forEach 外面,改为 page.close()。
const links = ['123', '456']
const linkBeginning = 'https://www.link.com/store/item/'
;(async () => {
const browser = await puppeteer.launch({
headless: false //preferably would run with true
})
links.forEach( async link => {
const page = await browser.newPage()
const session = await page.target().createCDPSession()
await session.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath: './pdf/'
})
await page.goto(linkBeginning + link)
await page.close() // Don't use browser.close() inside loop
})
await browser.close() // Use here instead
})()
您不需要 puppeteer 来执行此操作,并且您可以在 NodeJS 中相当轻松地实现它:
import http from "https";
import fs from "fs";
(async () => {
const skus = ["00548", "03575"];
const filesPromiseArray = skus.map(
(sku) =>
new Promise((resolve, reject) => {
const file = fs.createWriteStream(`${sku}.pdf`);
const request = http.get(`https://www.sols-europe.com/gb/pdfpublication/pdf/product/sku/${sku}`, (response) =>
response.pipe(file)
);
file.on("finish", resolve);
file.on("error", reject);
})
);
try {
await Promise.all(filesPromiseArray);
} catch {
console.log("There was an error downloading one of the files");
}
})();
这段代码在做什么?
- 使用您的
skus
数组,我们正在使用.map()
将它们转换为请求数组。 - 在
.map()
中,我们正在创建一个Promise
,它将在文件完成下载时成功 (resolve
),如果下载错误。 - 然后我们
await
我们刚刚创建的所有请求。如果其中之一失败,它将记录。
注:
如果您使用的是 CommonJS(package.json
中的 "type":"commonjs",
),请将两个导入替换为:
const http = require('https');
const fs = require('fs');