需求場(chǎng)景
獲取網(wǎng)站點(diǎn)擊的下載pdf,并把pdf重命名再上傳到COS云上面
技術(shù)使用
“puppeteer”: “^19.7.2”,
“egg”: “^3.15.0”, // 服務(wù)期用egg搭的
文件服務(wù)使用COS騰訊云
核心思路
獲取瀏覽器下載事件,并把文件保存到本地
const session = await substitutePage.target()
.createCDPSession();
await session.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath, // 指定文件保存路徑回家
});
在保存到本地前監(jiān)聽此文件夾,如果有文件則獲取并上傳
加timer做防抖是為了防止在文件寫入時(shí)以及重命名文件時(shí)多次觸發(fā)watch函數(shù),導(dǎo)致出會(huì)出現(xiàn)0KB源文件臟數(shù)據(jù)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-851973.html
let timer: any = null;
fs.watch(downloadPath, async (_eventType, filename) => {
if (timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(() => {
// 防止出現(xiàn)下載的臨時(shí)文件就觸發(fā)
if (filename.endsWith('.pdf')) {
resolve({
filename,
});
}
}, 500);
});
完整代碼
const session = await substitutePage.target()
.createCDPSession();
await session.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath, // 指定文件保存路徑回家
});
// res就是文件相關(guān)信息了
const [ res ] = await this.downloadPdfHandler(substitutePage, downloadPath);
// filePath就是自己本地的文件所在絕對(duì)路徑
const filePath = `${downloadPath}/${res.fileName}`;
// uploadFile是cos文件上傳相關(guān)實(shí)現(xiàn), 我就不放了,有私密的key
const pdfUriCode = await this.uploadFile(filePath, filePath);
const pdfUri = decodeURIComponent(pdfUriCode);
this.domainList = {
pdfSize: res.pdfSize,
pdfUri: pdfUri.substring(pdfUri.indexOf('root')),
};
downloadPdfHandler函數(shù)實(shí)現(xiàn)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-851973.html
downloadPdfHandler(page, downloadPath): Promise<any> {
const uuidName = uuidv4();
const fsWatchApi = () => {
// 使用防抖是為了防止下載的文件沒(méi)有寫入完全就重命名,那樣會(huì)產(chǎn)生一個(gè)臟文件
let timer: any = null;
return new Promise<{ filename: string }>(resolve => {
fs.watch(downloadPath, async (_eventType, filename) => {
if (timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(() => {
// 防止出現(xiàn)下載的臨時(shí)文件就觸發(fā)
if (filename.endsWith('.pdf')) {
resolve({
filename,
});
}
}, 500);
});
});
};
function responseWatchApi() {
return new Promise<void>(resolve => {
page.on('response', async response => {
// 檢查響應(yīng)是否為application/octet-stream且可能包含PDF(或你期望的其他文件類型)
if (response.headers()['content-type'].startsWith('application/octet-stream')) {
resolve();
}
});
});
}
return new Promise(async (resolve, reject) => {
try {
const [ , { filename }] = await Promise.all([ responseWatchApi(), fsWatchApi() ]);
const oldFilePath = path.join(downloadPath, filename);
const newFilePath = path.join(downloadPath, `${uuidName}.pdf`);
try {
fs.renameSync(oldFilePath, newFilePath);
this.logger.info(`文件名已經(jīng)被修改完成:${uuidName}`);
} catch (error) {
this.logger.info(`文件名已經(jīng)被修改完成:${uuidName}`);
}
await this.sleep(5 * 1000);
const files = fs.readdirSync(downloadPath);
// 創(chuàng)建一個(gè)數(shù)組,將文件名和其mtime(最后修改時(shí)間)一起存儲(chǔ)
const filesWithMtime = files.map(file => {
const filePath = path.join(downloadPath, file);
const stats = fs.statSync(filePath);
return { fileName: file, mtime: stats.mtime, size: stats.size };
});
const newestFile = filesWithMtime.sort((a, b) => b.mtime.getTime() - a.mtime.getTime())[0];
this.logger.info('newestFile: %o', {
newestFile,
});
resolve({
pdfSize: newestFile.size,
fileName: newestFile.fileName,
});
} catch (e) {
reject(e);
}
});
}
到了這里,關(guān)于使用puppeteer完成監(jiān)聽瀏覽器下載文件并保存到自己本地或服務(wù)器上完成上傳功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!