文件上传
Puppeteer框架中已经封装了文件上传方法,在需要文件上传的页面调用该方法即可完成文件上传。
但是!uploadFile can only be called on an input element.
uploadFile方法仅适用于上传元素是input标签的情况!!
请看下面的案例。 附赠 上传文件演示系统 以供学习
const puppeteer = require('puppeteer');
const path = require('path');// 引入path,供后面使用
(async () => {
const args = [
'--no-sandbox', // 沙盒模式
'--disable-setuid-sandbox', // uid沙盒
'--disable-infobars',
'--window-position=0,0',
'--ignore-certifcate-errors',
'--ignore-certifcate-errors-spki-list',
'--user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3312.0 Safari/537.36"',
'--disable-gpu', // GPU硬件加速
'--disable-dev-shm-usage', // 创建临时文件共享内存
'--no-first-run', // 没有设置首页。在启动的时候,就会打开一个空白页面。
'--no-zygote',
'--single-process' // 单进程运行
];
const options = {
args,
headless: false,
ignoreHTTPSErrors: true,
slowMo: 250,
defaultViewport: { width: 1920, height: 1080 }
};
const browser = await puppeteer.launch(options);
const browserWSEndpoint = browser.wsEndpoint();
const page = await browser.newPage();
page.goto("http://demo.codingyun.com/demo/upload");
await page.waitForSelector('input[type="file"]');
//添加等待语句,保证上传文件的元素已显示在页面上后,再进行下一步操作
const uploadFileHandle = await page.$('input[type="file"]');
await uploadFileHandle.uploadFile(__dirname+'/test.jpg');
//上传文件,这里文件地址是基于代码根目录的相对地址
await page.waitForTimeout(3000);
//这里调用了包好的一个固定时间等待方法,方便查看文件是否真正已上传成功
await page.click('#createPeriadBtn');//上传之后的后续操作
// puppeteer-expect
// page.goto("http://demo.codingyun.com/demo/upload");
// await page.waitForTimeout(3000);
// await expect(page).toUploadFile(
// 'input[type="file"]',
// path.join(__dirname, '/test.jpg'),
// );
// //puppeteer-expect提供了上传文件的方法,按官方文档提示此方法可以实现自动等待,但经过验证发现,在调用上传文件的方法前需要写入等待语句,否则案例会运行失败
// await page.waitForTimeout(3000);
// page.close();
// browser.close();
})();
//-------puppeteer---------
page.goto("http://demo.codingyun.com/demo/upload");
await page.waitForSelector('input[type="file"]');
//添加等待语句,保证上传文件的元素已显示在页面上后,再进行下一步操作
const uploadFileHandle = await page.$('input[type="file"]');
await uploadFileHandle.uploadFile(__dirname+'/test.jpg');
//上传文件,这里文件地址是基于代码根目录的相对地址
await page.waitForTimeout(3000);
//这里调用了包好的一个固定时间等待方法,方便查看文件是否真正已上传成功
await page.click('#createPeriadBtn');//上传之后的后续操作
//-------puppeteer-expect---------
// page.goto("http://demo.codingyun.com/demo/upload");
// await page.waitForTimeout(3000);
// await expect(page).toUploadFile(
// 'input[type="file"]',
// path.join(__dirname, '/test.jpg'),
// );
// //puppeteer-expect提供了上传文件的方法,按官方文档提示此方法可以实现自动等待,但经过验证发现,在调用上传文件的方法前需要写入等待语句,否则案例会运行失败
// await page.waitForTimeout(3000);
总结:
- 要完成文件上传,首先需要添加等待语句,保证“上传文件”页面元素已显示在web应用页面上
- 接着调用puppeteer提供的方法或者puppeteer-expect提供的上传文件方法上传,传入的文件地址写相对地址即可
- 真实项目中,如果有上传文件场景,需要把上传的文件和代码放在一起。
否则…file not exist or is not readable
文件下载
本质:Web应用中往往是点击某个链接、图片等完成下载操作,总的来说都是点击页面某个元素。所以,实现文件下载实际就是点击页面的目标元素,和之前讲过的点击操作相同,唯一的差别是:可以指定下载的文件存放位置。
请看案例:
(async () => {
let browser = await puppeteer.launch({headless: false});
let page = await browser.newPage();
let url='https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=icon&step_word=&hs=0&pn=12&spn=0&di=7108135681917976577&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=0&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=undefined&cs=412601273%2C4123436044&os=554748102%2C2278718741&simid=412601273%2C4123436044&adpicid=0&lpn=0&ln=1888&fr=&fmq=1657097287243_R&fm=&ic=undefined&s=undefined&hd=undefined&latest=undefined©right=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fi-1.lanrentuku.com%2F2020%2F11%2F5%2Ffdcf7d25-b846-464c-9df1-86a9169d71e5.png%3FimageView2%2F2%2Fw%2F500%26refer%3Dhttp%3A%2F%2Fi-1.lanrentuku.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1659689310%26t%3Da606448ba31034f7b85eb64cd21141e6&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bswg6jgp7h7_z%26e3Bv54AzdH3Ff7vwtAzdH3F0l9ac_z%26e3Bip4s&gsm=d&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCwzLDYsMSw0LDIsNSw4LDcsOQ%3D%3D';
await page.goto(url);
//打开一个存在文件下载链接的web页面
//通过 CDP 会话设置下载路径
const cdp = await page.target().createCDPSession();
//如果无此行代码,下载的文件存放到默认下载路径中,如果添加此语句,可以通过downloadPath指定下载的文件存放路径.
await cdp.send('Page.setDownloadBehavior', {
behavior: 'allow', //允许所有下载请求
downloadPath: 'public/js/imgs' //设置下载路径
});
//点击按钮触发下载
await (await page.waitForSelector('.btn-download')).click();
//等待文件出现,轮训判断文件是否出现
// await waitForFile('D:/phpstudy_pro/WWW/autotest/public/js/1.jpg');
await page.waitForTimeout(5000);
//等待语句,方便查看是否下载过程
// 因为有弹窗所以 此时为了防止 element is not defined 错误我们应该监听此页面元素是否弹出
// await page.waitForSelector('#dismiss-button',{timeout:7000});
// const searchPopout = await page.$("#dismiss-button");
// if (searchPopout) await page.click('#dismiss-button');
await page.close();
await browser.close();
}
)();
亲测效果一般!
所以我更推荐,通过获取目标 url 路径下载目标文件。而不是通过点击事件
(async () => {
let browser = await puppeteer.launch({headless: false});
let page = await browser.newPage();
await page.goto('http://pic.sogou.com/', { timeout: 0 });
await page.waitForSelector('#formid > input')
await page.focus("input[name^='query']")
// 模拟用户输入图片主题并按下Enter回车键 跳转
await page.keyboard.type(textType);
await page.keyboard.down('Enter');
//等待元素加载之后,否则获取不异步加载的元素
await page.waitForSelector('.figure-result-list');
let links = await page.$$eval('ul.figure-result-list > li > div.img-layout > a.img-height > img', links => {
return links.map(img => {
return {
href: img.src.trim()
}
});
});
let img_box = links.length
// console.log(links.length);
const aTags = links.splice(0, img_box);//全取弥补部分图片路径undefined状况
let max = img_box > Max ? Max : img_box;
for (var j = 1; j < max; j++) {
// let k = Math.floor(Math.random() * img_box + 1)
let a = aTags[j];
if (a.href == undefined) {
max += 1;
continue;
}
console.log(a.href);
let filename = DirPath + "/items-" + j + ".png";
// 获取线上文件流信息,写入本地文件保存
const content = await getResourceContent(page, a.href);
const contentBuffer = Buffer.from(content, 'base64');
fs.writeFileSync(filename, contentBuffer, 'base64');
}
// puppeteer 从浏览器缓存中拿文件,js,压缩文件等
async function getResourceTree(page) {
var resource = await page._client.send('Page.getResourceTree');
return resource.frameTree;
}
async function getResourceContent(page, url) {
const { content, base64Encoded } = await page._client.send(
'Page.getResourceContent',
{ frameId: String(page.mainFrame()._id), url },
);
assert.equal(base64Encoded, true);
return content;
};
await page.close();
await browser.close();
}
)();