Chrome 自动化交互利器:用 tampermonkey 向页面注入自定义 Javascript
1、背景
经常会遇到类似下面的这种网站,查个信息得填一堆信息,奇葩的是文本框也不让复制粘贴,而且浏览器还不自动保存,这样每次查询或者超时退出都得重新手动填写一遍。
有没有办法能简化这个过程呢?
办法当然是有的,其中最通用的办法是装个 lastpass 扩展,由它帮你完成表单信息的自动保存与填充,信息也会云存储在他们服务器上,还是挺方便的。
但是如果你担心隐私安全或者想要更加个性化的功能怎么办?一般来说这个时候需要用户自定义脚本来实现了。
2、tampermonkey 简介
Chrome是原生支持加载UserScripts的,只不过它的加载方式是将UserScripts文件转换为一个扩展…… 开发起来略麻烦,不过好处就是稳定可靠。不过这个方案在这里就比较重量级了,不够方便。 所以我决定用TamperMonkey来做这件事儿。 安利一下TamperMonkey扩展,这个相当于Firefox上的Scriptish或GreaseMonkey扩展,相当于一个UserScripts的管理和加载器。挺好使的一个玩意儿,作者貌似是位棒子国的同胞,只不过这货对Chrome的性能影响还是蛮大的。
3、用 tampermonkey 实现自动化交互
首先你需要安装好 Chrome 以及 tampermonkey 插件,然后在你需要自动交互的网站上点击扩展图标,这样你就可以开始写你的交互逻辑代码了:
上面是一个很通用的模板,如果你看不懂的话也许需要去看下UserScripts的格式…… 这里先把 @name
和 @match
改掉,一个是名字,一个是匹配的网址。名字随便取,@match
改为 http://www.ooxx.com/*
。 然后在最下面开始写代码。
比如文初开头的完整代码如下:
// ==UserScript==
// @name ooxx网站
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match http://www.ooxx.com/wsyw/wscx/gjjcx-logineoor.jsp?id=2
// @grant none
// ==/UserScript==
/* jshint -W097 */
'use strict';
// Your code here...
(function () {
document.getElementsByTagName("option")[1].selected = true;
document.form1.bh.value = "ID:NO";
document.form1.mm.value = "passwd";
//function post(path, params, method) {
// method = method || "post"; // Set method to post by default if not specified.
//
// // The rest of this code assumes you are not using a library.
// // It can be made less wordy if you use one.
// var form = document.createElement("form");
//
// form.setAttribute("method", method);
// form.setAttribute("action", path);
//
// for (var key in params) {
// if (params.hasOwnProperty(key)) {
// var hiddenField = document.createElement("input");
// //hiddenField.setAttribute("type", "hidden");
// hiddenField.setAttribute("name", key);
// hiddenField.setAttribute("value", params[key]);
//
// form.appendChild(hiddenField);
// }
// }
//
// var iframe = document.createElement("iframe");
// //document.body.appendChild(iframe);
// //document.querySelector("iframe").contentWindow.document.childNodes[0].appendChild(form);
// //form.submit();
//
//}
//
//post('http://lab.ocrking.com/do.html', {
// url : 'http://www.ooxx.com/wsyw/servlet/PicCheckCode1',
// service : 'OcrKingForCaptcha',
// language : "eng",
// charset : "7",
// outputFormat : "",
// email : ""
//});
})();
这样当你每次打开 http://www.ooxx.com/wsyw/wscx/gjjcx-logineoor.jsp?id=2 时,下拉列表会被选择好,同时各个表单域的值也会填写成预设值,如果验证码也破解成功则可以直接模拟点击事件提交表单,文章开头提到的繁琐流程至此一气呵成十分方便!
关于最后一个验证码的破解有两种思路:
- 利用Canvas进行验证码识别,属于纯 js 破解,需要针对性的分析验证码的色彩与位置分布特点等,兼容性不好
- 利用云服务来破解,不过这种需要注意 Ajax 跨域问题,推荐使用 js 构造iframe,然后嵌套 form 表单提交 post 的方式来请求服务
这两点思路可以参考文末的 Refer 链接。
4、个性化需求:目标页自动输入百度网盘密码
我们应该经常能遇到上面的 case,每次都要打开链接,然后再返回回来复制密码,再切到下一页面,再粘贴回车,太繁琐啦。
咱们可以看看在 tampermonkey 中如何将这几个交互步骤自动化。
4.1 给跳转 url 带上尾巴
要想在下一页还能拿到上一页密码,只有两种办法,一种是 url 传参,另一种是 Cookie 传递。
这里咱们优先选择 url 传参的方式,基本意思就是找出所有指向百度网盘、360云盘的A标签,然后尝试在A标签后面的文本或A标签当前上级节点里搜索提取码,一旦找到的话,就将其以Hash的方式附加到链接中。
4.2 提取密码并模拟点击
从上一步中的 URL Hash 中截取密码并赋值给密码框,最后模拟点击事件即可。
代码最终如下:
// ==UserScript==
// @name zdfans
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match http://www.zdfans.com/*
// @grant none
// ==/UserScript==
/* jshint -W097 */
'use strict';
// Your code here...
// 4.1
document.querySelectorAll("a[href*='pan.baidu.com'], a[href*='yunpan.cn']").forEach(
function(link){
var txt=link.nextSibling&&link.nextSibling.nodeValue;
var code=/码.*?([a-zd]{4})/i.exec(txt)&&RegExp.$1;
if(!code){
txt=link.parentNode.innerText;
code=/码.*?([a-zd]{4})/i.exec(txt)&&RegExp.$1;
}
if(code){
var href=link.getAttribute("href");
link.setAttribute("href", href+"#"+code);
}
}
);
// 4.2
var pathname=self.location.pathname;
!function(){
if(pathname.indexOf("/share/")!==-1&&document.getElementById("accessCode")){
var code=self.location.hash.slice(1,5);
if(/[a-zd]{4}/i.exec(code)){
document.getElementById("accessCode").value=code;
document.getElementById("submitBtn").click();
}}
}();
需要说明的是,虽然效果很好很赞,但最大的问题是:需要跑UserScripts。所以一般在常去的资源站上用用就好了,没必要把脚本跑到每个网站上,毕竟那是极浪费性能的事儿~
上面我只匹配了zdfans网站,但其实只要改@match
,这段脚本可以匹配大多数使用网盘共享的网站。
最后感谢 木魚 童鞋提供的思路与分享,其实引申开来,TamperMonkey 用于一些自动化交互测试以及一些什么秒杀活动自动输入等场合也是极好的,就看大家怎么拿着锤子满世界找钉子了~ :)
Refer:
[1] 技术贴:使用UserScript自动通过百度网盘/360云盘提取码
http://blog.fishlee.net/2016/03/09/using-contentscripts-to-pass-access-code/
[2] Javascript : get <img> src and set as variable?
http://stackoverflow.com/questions/7882356/javascript-get-img-src-and-set-as-variable
[3] 使用Canvas进行验证码识别
http://www.cnblogs.com/ziyunfei/archive/2012/10/05/2710349.html
[4] JS破解乌云验证码
http://zone.wooyun.org/content/18101
[5] OCR 在线识别验证码
[6] UserScript:自动提取XClient上的下载链和提取码
http://blog.fishlee.net/2016/03/18/userscipts-pass-xclient-downloadlink/
- React Native实现一个自定义模块
- 微信小程序实战教程:火车票查询(含demo)
- NGS基础 - FASTQ格式解释和质量评估
- 数据结构之串
- 生信宝典之傻瓜式 (一) 如何提取指定位置的基因组序列
- 注意map<> 的[]
- 生信宝典之傻瓜式 (二) 如何快速查找指定基因的调控网络
- React Native组件只Image
- 数据结构之线性表
- 生信宝典之傻瓜式 (三) 我的基因在哪里发光 - 如何查找基因在发表研究中的表达
- 谈谈 char *num="123";和char num[4]="123";的区别
- 未越狱的iPhone/iPad也中招:走近强大的间谍软件XAgent与MadCap
- 【年末收藏】17个新手常见Python运行时错误
- C++ STL之priority_queue
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法