使⽤Puppeteer进⾏数据抓取(四)——图⽚下载
⼤多数情况下,图⽚获取并不是很困难的事情,获取图⽚的url,然后模拟浏览器请求即可。但是,有的时候这种⽅法往往⽆法⽣效,常见的情形有:
1. 动态图⽚,每次获取都是⼀个新的,例如图⽚验证码,重新获取时是⼀个新的验证码图⽚,已经失去了效果了。
2. 动态上下⽂,有的⽹站为了反爬⾍,获取图⽚时要加上其动态⽣成的cookie才⾏。
svg图这些情况下,使⽤puppeteer驱动chrome浏览器能看到图⽚,但获取url后单独请求时,要么获取到的图⽚⽆效,要么获取不到图⽚。本⽂这⾥就简单的介绍下⼀些⼗分通⽤且有效的下载这些图⽚的⽅法。
截图:
截图是⼀种⾮常简单除暴的⽅法,⼤多数的时候也是最⽅便有效的。特别是对于验证码之类的动态⽣成的图⽚,这些验证码获取原始图⽚往往需要⼀定时间的分析,但chrome能直接截取渲染后⽣成的图⽚,直接跳过了分析过程,⼗分⽅便。
这⾥以⽹为例,截取它登陆的验证码。
⾸先⽤devtool分析其selector path。
发现其为"#codePic",接下来的操作就⾮常简单了
('v/sipopublicsearch/portal/uiIndex.shtml');
const image = await page.waitForSelector('#codePic');
await image.screenshot({
path: '验证码.png',
omitBackground: false
});
这⾥⽤的并不是page.screenshot,因为那样对整个页⾯截图了,⽽是⾸先获取验证码图⽚的Element
Handle,然后调⽤ElementHandle.screenshot只对该元素截图。
这种⽅式⾮常简单有效,但由于是通过渲染的⽅式获取的数据,还是丢失了原始信息的,例如,svg图⽚就丢失了⽮量信息了。
从缓存中读取
另外⼀种思路是直接从chrome缓存中的数据读取图⽚数据,就像chrome dev tool的source tab中的那样
这个功能在puppeteer中并没有封装,在中是有的,它主要涉及到如下两个api:
它可以⽤来获取资源树,就像上图左边所⽰:
它可以⽤来获取资源内容,它需要两个参数,frameid和url。frameid可以从page中获取,url必须是前⾯getResourceTree中获取的url。
虽然puppeteer没有封装这两个函数的功能,但还是有⼀个私有接⼝page._client.send可以发送原始dev protocol指令。这⾥我们可以简单的封装⼀下:
async function getResourceTree(page) {
var resource = await page._client.send('ResourceTree');
return resource.frameTree;
}
const assert = require('assert');
async function getResourceContent(page, url) {
const { content, base64Encoded } = await page._client.send(
'ResourceContent',
{ frameId: String(page.mainFrame()._id), url },
);
assert.equal(base64Encoded, true);
return content;
};
此时就说明我们可以利⽤前⾯的api获取该图⽚了。
const fs = require('fs');
await page.waitForSelector('#codePic');
const url = await page.$eval('#codePic', i => i.src);
const content = await getResourceContent(page, url);
const contentBuffer = Buffer.from(content, 'base64');
fs.writeFileSync('验证码.png', contentBuffer, 'base64');
这种⽅式并不限于只获取图⽚,也可以获取原始的js,svg之类的资源。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论