puppeteer 学习笔记
因为 OI 学不下去了,所以整天搞一些小玩意。
安装
首先安装 node.js、node.exe,配置好环境变量等之后进行以下操作:
在工作目录下执行:
npm install express -g
npm install puppeteer
然后每次在当前目录中执行
node xxx.js [$value]
即可执行。
使用
python 爬虫可以拿下多数情况下的爬虫操作,但遇到动态 js 之类的玩意就不太行了。
这个时候 puppeteer 的模拟浏览器行为可以解决这个问题。py 也有类似的东西,但是有谷歌官方做支持的 puppeteer 的 bug 等会少一些。
0.实例创建与基本操作
我们可以通过以下代码创建一个实例:
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({headless: false});
// true 为不观看操作过程
// executablePath: "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"
const page = await browser.newPage();
await page.goto(Url, {timeout: 0, waitUntil: 'load'});
await browser.close() // 关闭浏览器
page 有如下常用操作:
await page.goto(url); // 前往某个 url
await page.reload(); // 刷新
cookies=[{/*something*/},{...}];
await page.setCookie(...cookies); // 设置cookies,注意格式
await page.close(); //关闭当前页
await page.waitForTimeout(/*Time (ms)*/);
await page.waitForSelector('selector');
await page.waitForXpath('xpath');
await page.waitForNavigation(); // 等待页面完全加载完成。
有时 cmd 命令中需要传入一些参数,可以直接带在 .js 文件后面。
const value = process.argv[2]; // 2 为取出 .js 后第一项
/*
如: node test.js https://www.baidu.com
那么将取出 https://www.baidu.com
*/
console.log(value) // 输出在标准输出中
数字代表项数,用空格分开。
更多操作见官方文档.许多 js 基本操作与 c++ 类似甚至完全一样。
1.获取页面元素
可以通过 selector 或 xpath 获取元素。
const element = await page.$eval('selector', el => el.something);
const value = await page.$x('xpath');
await value[0].click();
这将获取整个元素,具体要取出哪些内容要自己选择。select 便于获得一些 href 之类的玩意,xpath 则被我用于点击。
xpath获取的元素有若干属性,可通过通配符获取子节点个数:
const ele = await page.$x('//*[@id="comicContain"]/*');
const len = ele.length;
2.输入/点击/截图
实时获取命令行输入需要引入 readline-sync 库。
输入与点击操作:
await (await page.$x('xpath'))[0].type(something_to_type); // 通过某个xpath获取元素并输入
await (await page.$x('xpath'))[0].click(); // 选择元素并点击
await page.keyboard.press('[option]'); // 按一下
await page.keyboard.down('[option]'); // 按着
await page.keyboard.up('[option]'); // 松开
有时需要对某个元素截图并保存,可以通过以下代码实现:
async function screenshotDOMElement(page, selector, path, padding = 0) {
const rect = await page.evaluate(selector => {
try{
const element = document.querySelector(selector);
const {x, y, width, height} = element.getBoundingClientRect();
if(width * height != 0){
return {left: x, top: y, width, height, id: element.id}; }
else { return null; }
}catch(e){return null; }
}, selector);
return await page.screenshot({path: path, clip: rect ? {x: rect.left - padding, y: rect.top - padding, width: rect.width + padding * 2, height: rect.height + padding * 2 } : null });
}
// 传入: page实例、selector选择器、path保存路径.
获得交互的方法如下:
var v_type = readlineSync.question('Some Output with the question');
那么 v_type 中就获得了实时的输入。
3.文件下载\保存
文件系统相关操作需要引入 fs 库。
文件路径相关操作则需要引入 path 库。
文件下载操作通过点击操作触发。
const cdp = await page.target().createCDPSession();
save_path = '';
await cdp.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath: path.resolve(__dirname, `${save_path}`)
// path 的这个格式比不可少,save_path 是真正的路径。
}); // 文件下载相关行为
对于保存路径可能不存在的情况,可以通过如下代码完成路径创建。
async function dirExists(savepath) { whole = savepath.split('\\'); var now = whole[0];
for (var i = 1; i < whole.length; ++i) {
now = now + '\\' + whole[i];
if (!fs.existsSync(now)) {
fs.mkdirSync(now); console.log(`File ${now} is not exist, now is making...`); }
}
}
文件写入操作也可以通过 fs 的 write 操作完成。
未完待续……