技术标签: node chrome自动登录 puppeteer 自动登录 chrome插件开发
之前写了个chrome 扩展来完成公司内部的一个需求。在一个网站上实现了自动化程序,包括登录,后续操作,保持状态,被踢出后再次登录等等。
但是这个网站突然前几天更新了登录方式,在登录页面嵌入了iframe,使用内嵌的iframe登录。我还是用chrome扩展试了一下,但是chrome扩展无法操作iframe。
只能转换思路,最终群友提供了一个线索,找到了一个google官方出的node包 puppeteer
,顺利的完成了自动登录的流程。只能说这个包真强大,群友玩的真多。
所以以下内容和代码都为了解决一个问题: 使用 puppeteer 自动登录内嵌 iframe 页面登录的的网页,并监控到登录状态失效后,自动再次登录
本文默认您会使用 node
和 npm
, 以下脚本基于node14.15.0,在node 12版本上运行通过
"devDependencies": {
"carlo": "^0.9.46",
"puppeteer-core": "^5.4.0"
}
puppeteer
和 puppeteer-core
的区别
puppeteer
的核心是puppeteer-core
,puppeteer
会下载 Chromium
,而 puppeteer-core
不会自动下载 Chromium
。puppeteer
运行时默认使用 puppeteer-core
来驱动 Chromium
,puppeteer
还能配置 PUPPETEER_*
。我这里使用了puppeteer-core
,调用本地 google chrome
。
准备工作
const puppeteer = require('puppeteer-core');
//find_chrome模块来源于GoogleChromeLabs的Carlo,可以查看本机安装Chrome目录
const findChrome = require('./node_modules/carlo/lib/find_chrome');
const width = 1366; //浏览器宽度
const height = 768; //浏览器高度
let browser = null
, page = null
, init = false // 初次运行脚本
, isOk = false; // 触发登录事件开关
以上导入了必须的模块,提前声明了需要的数据
1 传入配置 创建浏览器对象
const newBrowser = async () => {
init = true; // 已经创建了浏览器对象
let findChromePath = await findChrome({
});
let executablePath = findChromePath.executablePath; //得到本机chrome路径
browser = await puppeteer.launch({
executablePath, // 本地chrome路径
headless: false, // 启用页面GUI方式
devtools: false, // F12打开控制台
args: [
`--disable-extensions-except=/Users/mac/project/debug/rechargenew`, // 不屏蔽这个扩展
`--window-size=${
width},${
height}`, // 窗口大小
`–disable-gpu` // 禁用 GPU加速
],
defaultViewport: {
width: width, height: height } // 页面大小
});
page = await browser.newPage(); // 创建浏览器
newhtml()
}
此时到这里桌面就会打开一个chrome浏览器
2 打开指定的页面
// 创建打开google页面
const newhtml = async () => {
await page.goto('http://www.xxxx.com/', {
waitUntil: 'networkidle2'
});
startLogin()
}
运行到这里会打开指定页面
3 开启自动登录
// 开始登录
const startLogin = async (callback) => {
const startLogin = await page.$(".submit-btn");
if (startLogin) {
page.click(".submit-btn")
}
// 检测到 iframe 请求返回回来了 再等5秒钟开始自动填写账号密码登录
page.on('response', async req => {
// 判断当前这个请求是不是请求 iframe 登录页面
if (req.url().indexOf('xxxx.xxxx.com/xxxx') >= 0 && !isOk) {
isOk = true // 阻止重复运行
setTimeout(async () => {
await page.waitFor('[id*="xxxxx"]');//等待我的iframe出现
const frame = (await page.frames())[2]
frame.click("#tab-password")
await frame.waitFor(3000);
await frame.waitFor('.ruleForm-pwd .form-item1 input');//等待用户名框出现
await frame.type('.ruleForm-pwd .form-item1 input', 'xxxx');//输入用户名
await frame.waitFor('.ruleForm-pwd .passwordInput input');//等待密码输入框出现
await frame.type('.ruleForm-pwd .passwordInput input', 'xxxx');//输入密码
// 点击登录
setTimeout(() => {
frame.click(".loginBtnWrap .loginBtn")
setTimeout(() => {
page.click(".banner-info .submit-btn")
}, 2000);
}, 1000);
}, 5000);
}
});
}
在这里使用 page.on('response')
监听到特定的请求接口返回后,开始填入账号和密码准备登录
有些地方需要用到延时器等待dom或者js操作完成,才能进行下一步,这样较为保险。
检测登录状态是否失效
// 检查是否被踢出登录 被踢出登录后重新登录
setInterval(() => {
console.log(page.url());
if (page.url().indexOf("xxx.xxx.com/index.html?") >= 0 && init) {
isOk = false
newhtml()
}
}, 20000);
这里开启了一个定时器,判断当前宿主页面的url是否是登录页面的url,如果是登录页面的url,就判定当前登录状态已经失效了,然后再次重启登录流程。
完整代码:
const puppeteer = require('puppeteer-core');
//find_chrome模块来源于GoogleChromeLabs的Carlo,可以查看本机安装Chrome目录
const findChrome = require('./node_modules/carlo/lib/find_chrome');
const width = 1366;
const height = 768;
let browser = null
, page = null
, init = false // 初次运行
, isOk = false; // 触发登录事件开关
const newBrowser = async () => {
init = true;
let findChromePath = await findChrome({
});
let executablePath = findChromePath.executablePath;
browser = await puppeteer.launch({
executablePath,
headless: false,
devtools: false, // F12打开控制台
args: [
`--disable-extensions-except=/Users/mac/project/debug/rechargenew`, // 不屏蔽这个插件
`--window-size=${
width},${
height}`, // 窗口大小
`–disable-gpu`
],
defaultViewport: {
width: width, height: height } // 页面大小
});
page = await browser.newPage();
newhtml()
}
// 创建打开google页面
const newhtml = async () => {
await page.goto('http://www.xxxx.com/', {
waitUntil: 'networkidle2'
});
startLogin()
}
// 开始登录
const startLogin = async (callback) => {
const startLogin = await page.$(".submit-btn");
if (startLogin) {
page.click(".submit-btn")
}
// 检测到 iframe 请求返回回来了 再等5秒钟开始自动填写账号密码登录
page.on('response', async req => {
if (req.url().indexOf('xxxxx.xxxxxx.com/xxxx') >= 0 && !isOk) {
isOk = true // 阻止重复运行
setTimeout(async () => {
await page.waitFor('[id*="xxxxx"]');//等待我的iframe出现
const frame = (await page.frames())[2]
frame.click("#tab-password")
await frame.waitFor(3000);
await frame.waitFor('.ruleForm-pwd .form-item1 input');//等待用户名框出现
await frame.type('.ruleForm-pwd .form-item1 input', 'xxxxxxx');//输入用户名
await frame.waitFor('.ruleForm-pwd .passwordInput input');//等待密码输入框出现
await frame.type('.ruleForm-pwd .passwordInput input', 'xxxxx');//输入密码
// 点击登录
setTimeout(() => {
frame.click(".loginBtnWrap .loginBtn")
setTimeout(() => {
page.click(".banner-info .submit-btn")
}, 2000);
}, 1000);
}, 5000);
}
});
}
newBrowser()
// 检查是否被踢出登录 踢出登录后重新登录
setInterval(() => {
console.log(page.url());
if (page.url().indexOf("xxxxxxx.xxxxxxx.com/index.html?") >= 0 && init) {
isOk = false
newhtml()
}
}, 20000);
注意点
--disable-extensions-except
插件路径的写法,在mac中上面写法是正确的。在window中,\
字符需要替换成 /
,这里浪费了好多时间frame
dom树,page.frames()
返回的集合需要找到指定的frame,试了好多方法,最后直接暴力去2了参考连接
新手必须看的
大佬翻译的puppeteer文档
puppeteer之iframe1
puppeteer之iframe2
puppeteer之iframe3
微信群大佬都在等着你
微信扫描二维码加入微信群,交流学习,及时获取代码最新动态。
转自 https://blog.csdn.net/Bamboo_shui/article/details/72433523 (原文没第八章答案)数据结构(C语言版 第2版)课后习题答案 严蔚敏 等 编著,仅供参考,还是自己认真做了再看第1章 绪论 5.选择题(1)在数据结构中,从逻辑上可以把数据结构分成( C )。A.动态结构和静态结构 B.紧凑...
入口ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:bean*.xml"); /** * Main entry point. * @return {@code true} if the string matches agai...
什么是C语言函数int max(a,b)int a,b;{if (a>b) return a;else return b;}第一行说明max函数是一个整型函数,其返回的函数值是一个整数。形参为a,b。第二行说明a,b均为整型量。 a,b 的具体值是由主调函数在调用时传送过来的。在{}中的函数体内, 除形参外没有使用其它变量,因此只有语句而没有变量类型说明。 上边这种定义方法称为“传统格式”。...
扫描版书: 链接: https://pan.baidu.com/s/1ew2xPyQyFgBwz9J3lyoQKQ 提取码: 1sne答案: 链接: https://pan.baidu.com/s/1cgY-QwcQSZ9A8skwo5R8cg 提取码: ksu4
1、什么是 JdbcTemplate(1)Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作.2、搭建环境(1)引入相关 jar 包(2)在 spring 配置文件配置数据库连接池 <!--配置数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <pro
js-cookie github地址https://github.com/js-cookie/js-cookie使用方式npm install js-cookie --save引入js-cookieimport Cookies from 'js-cookie'使用js-cookie获取cookie对应的值import Cookies from 'js-cookie'// 获取...
2DRotationMatrix 2DRotationMatrix计算二维旋转的仿射变换矩阵 CvMat* cv2DRotationMatrix( CvPoint2D32f center, double angle,double scale, CvMat* map_matrix );center 输入图像的旋转中心坐标 angle 旋转角
2302: [HAOI2011]Problem cTime Limit:30 SecMemory Limit:256 MBSubmit:648Solved:355[Submit][Status][Discuss]Description给n个人安排座位,先给每个人一个1~n的编号,设第i个人的编号为ai(不同人的编号可以相同),接着从第一个人开始,大家依次入座,第...
JQuery鼠标移到图片改变,移出图片恢复原来图片<script src="js/jquery-1.11.2.min.js"></script> <script type="text/javascript">$(document).ready(function(){ $(".imgdiv").mouseover(function(){ $(".imgsrc").attr("src","images/adver2.jpg");
1、环境(1)操作系统:Windows server 2003、Windows server2008(2)JDK:jdk 1.6(3)apache-tomcat-6.0.35(注意版本号号,版本号6.0.18測试未通过)(4)网络:互联网、专网測试均通过。2、使用到的软件、jar包(1)Win32OpenSSL_Light-1_0_1
Docker简介•官网 www.docker.com• github https://github.com/docker/docker.github.io• 开源的容器引擎,可以让开发者打包应用以及依赖的库,然后发布到任何流行的linux发行版上,移植很方便• 由go语言编写,基于apache2.0协议发布• 基于linux kernel,要想在win下运行需要借助一个vm(...
一、简介Vuepress2.x 英文官网Vuepress2.x 中文官网二、安装参考步骤1:新建一个文件夹,如:Doc2.0步骤2:进入文件夹目录,新建 package.json,命令:npm init步骤3:安装本地依赖,我当时使用的是如下版本,可在此找到自己需要的npm i [email protected]步骤4:在 package.json 中添加如下信息"scripts": { "docs:dev": "vuepress dev