文件 上传/下载 操作

文件上传

Puppeteer框架中已经封装了文件上传方法,在需要文件上传的页面调用该方法即可完成文件上传。
但是!uploadFile can only be called on an input element.
uploadFile方法仅适用于上传元素是input标签的情况!!
请看下面的案例。 附赠 上传文件演示系统 以供学习
image.png

  1. const puppeteer = require('puppeteer');
  2. const path = require('path');// 引入path,供后面使用
  3. (async () => {
  4. const args = [
  5. '--no-sandbox', // 沙盒模式
  6. '--disable-setuid-sandbox', // uid沙盒
  7. '--disable-infobars',
  8. '--window-position=0,0',
  9. '--ignore-certifcate-errors',
  10. '--ignore-certifcate-errors-spki-list',
  11. '--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"',
  12. '--disable-gpu', // GPU硬件加速
  13. '--disable-dev-shm-usage', // 创建临时文件共享内存
  14. '--no-first-run', // 没有设置首页。在启动的时候,就会打开一个空白页面。
  15. '--no-zygote',
  16. '--single-process' // 单进程运行
  17. ];
  18. const options = {
  19. args,
  20. headless: false,
  21. ignoreHTTPSErrors: true,
  22. slowMo: 250,
  23. defaultViewport: { width: 1920, height: 1080 }
  24. };
  25. const browser = await puppeteer.launch(options);
  26. const browserWSEndpoint = browser.wsEndpoint();
  27. const page = await browser.newPage();
  28. page.goto("http://demo.codingyun.com/demo/upload");
  29. await page.waitForSelector('input[type="file"]');
  30. //添加等待语句,保证上传文件的元素已显示在页面上后,再进行下一步操作
  31. const uploadFileHandle = await page.$('input[type="file"]');
  32. await uploadFileHandle.uploadFile(__dirname+'/test.jpg');
  33. //上传文件,这里文件地址是基于代码根目录的相对地址
  34. await page.waitForTimeout(3000);
  35. //这里调用了包好的一个固定时间等待方法,方便查看文件是否真正已上传成功
  36. await page.click('#createPeriadBtn');//上传之后的后续操作
  37. // puppeteer-expect
  38. // page.goto("http://demo.codingyun.com/demo/upload");
  39. // await page.waitForTimeout(3000);
  40. // await expect(page).toUploadFile(
  41. // 'input[type="file"]',
  42. // path.join(__dirname, '/test.jpg'),
  43. // );
  44. // //puppeteer-expect提供了上传文件的方法,按官方文档提示此方法可以实现自动等待,但经过验证发现,在调用上传文件的方法前需要写入等待语句,否则案例会运行失败
  45. // await page.waitForTimeout(3000);
  46. // page.close();
  47. // browser.close();
  48. })();
  1. //-------puppeteer---------
  2. page.goto("http://demo.codingyun.com/demo/upload");
  3. await page.waitForSelector('input[type="file"]');
  4. //添加等待语句,保证上传文件的元素已显示在页面上后,再进行下一步操作
  5. const uploadFileHandle = await page.$('input[type="file"]');
  6. await uploadFileHandle.uploadFile(__dirname+'/test.jpg');
  7. //上传文件,这里文件地址是基于代码根目录的相对地址
  8. await page.waitForTimeout(3000);
  9. //这里调用了包好的一个固定时间等待方法,方便查看文件是否真正已上传成功
  10. await page.click('#createPeriadBtn');//上传之后的后续操作
  11. //-------puppeteer-expect---------
  12. // page.goto("http://demo.codingyun.com/demo/upload");
  13. // await page.waitForTimeout(3000);
  14. // await expect(page).toUploadFile(
  15. // 'input[type="file"]',
  16. // path.join(__dirname, '/test.jpg'),
  17. // );
  18. // //puppeteer-expect提供了上传文件的方法,按官方文档提示此方法可以实现自动等待,但经过验证发现,在调用上传文件的方法前需要写入等待语句,否则案例会运行失败
  19. // await page.waitForTimeout(3000);

总结:

  1. 要完成文件上传,首先需要添加等待语句,保证“上传文件”页面元素已显示在web应用页面上
  2. 接着调用puppeteer提供的方法或者puppeteer-expect提供的上传文件方法上传,传入的文件地址写相对地址即可
  3. 真实项目中,如果有上传文件场景,需要把上传的文件和代码放在一起。

否则…file not exist or is not readable

文件下载

本质:Web应用中往往是点击某个链接、图片等完成下载操作,总的来说都是点击页面某个元素。所以,实现文件下载实际就是点击页面的目标元素,和之前讲过的点击操作相同,唯一的差别是:可以指定下载的文件存放位置。
请看案例:

  1. (async () => {
  2. let browser = await puppeteer.launch({headless: false});
  3. let page = await browser.newPage();
  4. 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&copyright=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';
  5. await page.goto(url);
  6. //打开一个存在文件下载链接的web页面
  7. //通过 CDP 会话设置下载路径
  8. const cdp = await page.target().createCDPSession();
  9. //如果无此行代码,下载的文件存放到默认下载路径中,如果添加此语句,可以通过downloadPath指定下载的文件存放路径.
  10. await cdp.send('Page.setDownloadBehavior', {
  11. behavior: 'allow', //允许所有下载请求
  12. downloadPath: 'public/js/imgs' //设置下载路径
  13. });
  14. //点击按钮触发下载
  15. await (await page.waitForSelector('.btn-download')).click();
  16. //等待文件出现,轮训判断文件是否出现
  17. // await waitForFile('D:/phpstudy_pro/WWW/autotest/public/js/1.jpg');
  18. await page.waitForTimeout(5000);
  19. //等待语句,方便查看是否下载过程
  20. // 因为有弹窗所以 此时为了防止 element is not defined 错误我们应该监听此页面元素是否弹出
  21. // await page.waitForSelector('#dismiss-button',{timeout:7000});
  22. // const searchPopout = await page.$("#dismiss-button");
  23. // if (searchPopout) await page.click('#dismiss-button');
  24. await page.close();
  25. await browser.close();
  26. }
  27. )();

亲测效果一般!
所以我更推荐,通过获取目标 url 路径下载目标文件。而不是通过点击事件

  1. (async () => {
  2. let browser = await puppeteer.launch({headless: false});
  3. let page = await browser.newPage();
  4. await page.goto('http://pic.sogou.com/', { timeout: 0 });
  5. await page.waitForSelector('#formid > input')
  6. await page.focus("input[name^='query']")
  7. // 模拟用户输入图片主题并按下Enter回车键 跳转
  8. await page.keyboard.type(textType);
  9. await page.keyboard.down('Enter');
  10. //等待元素加载之后,否则获取不异步加载的元素
  11. await page.waitForSelector('.figure-result-list');
  12. let links = await page.$$eval('ul.figure-result-list > li > div.img-layout > a.img-height > img', links => {
  13. return links.map(img => {
  14. return {
  15. href: img.src.trim()
  16. }
  17. });
  18. });
  19. let img_box = links.length
  20. // console.log(links.length);
  21. const aTags = links.splice(0, img_box);//全取弥补部分图片路径undefined状况
  22. let max = img_box > Max ? Max : img_box;
  23. for (var j = 1; j < max; j++) {
  24. // let k = Math.floor(Math.random() * img_box + 1)
  25. let a = aTags[j];
  26. if (a.href == undefined) {
  27. max += 1;
  28. continue;
  29. }
  30. console.log(a.href);
  31. let filename = DirPath + "/items-" + j + ".png";
  32. // 获取线上文件流信息,写入本地文件保存
  33. const content = await getResourceContent(page, a.href);
  34. const contentBuffer = Buffer.from(content, 'base64');
  35. fs.writeFileSync(filename, contentBuffer, 'base64');
  36. }
  37. // puppeteer 从浏览器缓存中拿文件,js,压缩文件等
  38. async function getResourceTree(page) {
  39. var resource = await page._client.send('Page.getResourceTree');
  40. return resource.frameTree;
  41. }
  42. async function getResourceContent(page, url) {
  43. const { content, base64Encoded } = await page._client.send(
  44. 'Page.getResourceContent',
  45. { frameId: String(page.mainFrame()._id), url },
  46. );
  47. assert.equal(base64Encoded, true);
  48. return content;
  49. };
  50. await page.close();
  51. await browser.close();
  52. }
  53. )();