文件上传
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();})();
