使用 Tampermonkey 在 AngularJS 网站上自动提交表单?
Automate form submission, on an AngularJS website, using Tampermonkey?
我正在尝试在我没有源代码的网站上自动输入一些表单。找到合适的字段并用 js 填充它们并以编程方式提交表单是一项非常简单的任务。但是该网站是在 Angular 中构建的,当单击表单提交时,输入字段的所有验证标志都会弹出,就好像填写了 none 个字段一样。
浏览其他几篇文章后,我意识到我需要以某种方式在范围内设置变量,如下所示:
$scope.$apply(function() {
$scope.fieldName = varname;
});
或者将字段设置为脏,如下所示:
$scope.fieldname.$dirty = true;
不幸的是,由于无法访问代码,我不确定范围可能是什么,或者如何适当地告诉 Angular 表单上的字段已经以编程方式更新。
编辑
我使用 Roblox 作为此错误的示例。
网站上的不同表单,例如注册表(和登录后的表单)对其进行了验证,这会引发我提到的错误。
这是我尝试在注册脚本上使用与登录脚本相同的逻辑的示例:
// ==UserScript==
// @name Roblox Account Create
// @namespace http://roblox.com/
// @version 0.1
// @description Create Roblox Account
// @author You
// @match https://www.roblox.com/
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @grant none
// ==/UserScript==
/* jshint -W097 */
'use strict';
var _adj = [ 'Cool', 'Masked', 'Bloody', 'Lame' ];
var _animals = [ 'Hamster', 'Moose', 'Lama', 'Duck' ];
var _months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
var _username = _adj[ parseInt( Math.random( ) * _adj.length ) ], _pass = Math.random( ).toString( 36 ).substring( 2, 10 );
_username += _animals[ parseInt( Math.random( ) * _animals.length ) ];
_username += parseInt( Math.random( ) * 1000 );
var _dt_month = _months[ Math.floor( Math.random( ) * ( 12 ) + 0 ) ];
var _dt_day = Math.floor( Math.random( ) * ( 28 ) + 1 );
var _dt_year = Math.floor( Math.random( ) * ( 2005 - 1916 + 1 ) + 1916 );
$( '#Username' ).val( _username );
$( '#Password' ).val( _pass );
$( '#PasswordConfirm' ).val( _pass );
$( '#MonthDropdown' ).val( _dt_month );
$( '#DayDropdown' ).val( _dt_day );
$( '#YearDropdown' ).val( _dt_year );
$( '#FemaleButton' ).click( );
$( '#SignupButton' ).click( );
我尝试在更改值后将输入和更改事件都添加到我的调用中,但是在将验证更新为我添加到输入字段的值时没有任何变化。例如:
$( '#Username' ).val( _username ).trigger( 'input' ); // Also .trigger( 'change' )
您可以通过将它们添加到 Tampermonkey 并导航到 ssl roblox homepage.
来测试这两个脚本
关键是 Angular 代码(和类似的 JS)使用 change
事件来触发它们的验证器。所以,仅仅设置值是不够的;您还必须发送更改事件。
所以:
- 设置值。
- 发送更改事件。对于 Greasemonkey/Tampermonkey 脚本,您必须注意沙箱和这部分的 jQuery 冲突。
从未注入的用户脚本中使用 jQuery .change()
或 .trigger()
,很少起作用。发送适当的更改事件;见下文。
- 因为你
@require
d jQuery(好),但使用 @grant none
(坏),你的脚本导致页面崩溃,你会在控制台中看到各种错误.
- 该脚本存在竞争条件,并且经常在输入准备好之前触发。等待
window.load
似乎就足够了,但如果您应该看到更多的时间问题,您可能必须采取类似 waitForKeyElements()
的措施。
$('#SignupButton').click ();
可能存在其他时间问题如果是这样,那不在这个问题的范围内。
- 请勿使用此知识违反任何网站的服务条款。 (如果适用)
这样,脚本就变成了:
// ==UserScript==
// @name Roblox Account Create
// @match https://www.roblox.com/
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @grant GM_addStyle
// ==/UserScript==
var _adj = [ 'Cool', 'Masked', 'Bloody', 'Lame' ];
var _animals = [ 'Hamster', 'Moose', 'Lama', 'Duck' ];
var _months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
var _username = _adj[ parseInt( Math.random( ) * _adj.length ) ], _pass = Math.random( ).toString( 36 ).substring( 2, 10 );
_username += _animals[ parseInt( Math.random( ) * _animals.length ) ];
_username += parseInt( Math.random( ) * 1000 );
var _dt_month = _months[ Math.floor( Math.random( ) * ( 12 ) + 0 ) ];
var _dt_day = Math.floor( Math.random( ) * ( 28 ) + 1 );
var _dt_year = Math.floor( Math.random( ) * ( 2005 - 1916 + 1 ) + 1916 );
window.addEventListener ("load", function load () {
setControl ('Username', _username );
setControl ('Password', _pass );
setControl ('PasswordConfirm', _pass );
setControl ('MonthDropdown', _dt_month );
setControl ('DayDropdown', _dt_day );
setControl ('YearDropdown', _dt_year );
$( '#FemaleButton' ).click( );
$( '#SignupButton' ).click( );
} );
function setControl (elemID, value) {
var zInput = $( '#' + elemID );
zInput.val( value );
var changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("change", true, true);
zInput[0].dispatchEvent (changeEvent);
}
请注意,我们使用了一个有效的 @grant
值,而不是 none
。这对于避免与页面的 javascript.
冲突至关重要
事实证明,有几个不同的事件会触发各种网站上的验证(输入、键入、更改)。这是我使用的功能,它似乎适用于所有网站(jquery、angularjs 或普通的旧 javascript):
function fireChangeEvents(element){
var changeEvent = null;
changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("input", true, true);
element.dispatchEvent (changeEvent);
console.debug('input event dispatched for element: '+element.id);
changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("keyup", true, true);
element.dispatchEvent (changeEvent);
console.debug('keyup event dispatched for element: '+element.id);
changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("change", true, true);
element.dispatchEvent (changeEvent);
console.debug('change event dispatched for element: '+element.id);
}
在这种情况下,我认为 jquery 应该有效:
fireChangeEvents(document.getElementById('Username'));
您可能需要小心,仅在值实际更改时才触发 "change" 事件。我在每个 "change" 事件上看到复选框上的一些草率代码切换 "valid" 而不是读取实际的复选框值。
注意:在 chrome 46.0.2490.71(portable_apps 版本)
上测试
我无法使用此处的代码在 nextcloud 联系人应用程序(用 angular 编写)中设置联系人字段。这对我有用:
function setAngularInputValue (targetInput, newValue) {
targetInput.value = newValue;
const event = new Event('input', { bubbles: true });
targetInput.dispatchEvent(event);
}
我正在尝试在我没有源代码的网站上自动输入一些表单。找到合适的字段并用 js 填充它们并以编程方式提交表单是一项非常简单的任务。但是该网站是在 Angular 中构建的,当单击表单提交时,输入字段的所有验证标志都会弹出,就好像填写了 none 个字段一样。
浏览其他几篇文章后,我意识到我需要以某种方式在范围内设置变量,如下所示:
$scope.$apply(function() {
$scope.fieldName = varname;
});
或者将字段设置为脏,如下所示:
$scope.fieldname.$dirty = true;
不幸的是,由于无法访问代码,我不确定范围可能是什么,或者如何适当地告诉 Angular 表单上的字段已经以编程方式更新。
编辑
我使用 Roblox 作为此错误的示例。
网站上的不同表单,例如注册表(和登录后的表单)对其进行了验证,这会引发我提到的错误。
这是我尝试在注册脚本上使用与登录脚本相同的逻辑的示例:
// ==UserScript==
// @name Roblox Account Create
// @namespace http://roblox.com/
// @version 0.1
// @description Create Roblox Account
// @author You
// @match https://www.roblox.com/
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @grant none
// ==/UserScript==
/* jshint -W097 */
'use strict';
var _adj = [ 'Cool', 'Masked', 'Bloody', 'Lame' ];
var _animals = [ 'Hamster', 'Moose', 'Lama', 'Duck' ];
var _months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
var _username = _adj[ parseInt( Math.random( ) * _adj.length ) ], _pass = Math.random( ).toString( 36 ).substring( 2, 10 );
_username += _animals[ parseInt( Math.random( ) * _animals.length ) ];
_username += parseInt( Math.random( ) * 1000 );
var _dt_month = _months[ Math.floor( Math.random( ) * ( 12 ) + 0 ) ];
var _dt_day = Math.floor( Math.random( ) * ( 28 ) + 1 );
var _dt_year = Math.floor( Math.random( ) * ( 2005 - 1916 + 1 ) + 1916 );
$( '#Username' ).val( _username );
$( '#Password' ).val( _pass );
$( '#PasswordConfirm' ).val( _pass );
$( '#MonthDropdown' ).val( _dt_month );
$( '#DayDropdown' ).val( _dt_day );
$( '#YearDropdown' ).val( _dt_year );
$( '#FemaleButton' ).click( );
$( '#SignupButton' ).click( );
我尝试在更改值后将输入和更改事件都添加到我的调用中,但是在将验证更新为我添加到输入字段的值时没有任何变化。例如:
$( '#Username' ).val( _username ).trigger( 'input' ); // Also .trigger( 'change' )
您可以通过将它们添加到 Tampermonkey 并导航到 ssl roblox homepage.
来测试这两个脚本关键是 Angular 代码(和类似的 JS)使用 change
事件来触发它们的验证器。所以,仅仅设置值是不够的;您还必须发送更改事件。
所以:
- 设置值。
- 发送更改事件。对于 Greasemonkey/Tampermonkey 脚本,您必须注意沙箱和这部分的 jQuery 冲突。
从未注入的用户脚本中使用 jQuery.change()
或.trigger()
,很少起作用。发送适当的更改事件;见下文。 - 因为你
@require
d jQuery(好),但使用@grant none
(坏),你的脚本导致页面崩溃,你会在控制台中看到各种错误. - 该脚本存在竞争条件,并且经常在输入准备好之前触发。等待
window.load
似乎就足够了,但如果您应该看到更多的时间问题,您可能必须采取类似waitForKeyElements()
的措施。 $('#SignupButton').click ();
可能存在其他时间问题如果是这样,那不在这个问题的范围内。- 请勿使用此知识违反任何网站的服务条款。 (如果适用)
这样,脚本就变成了:
// ==UserScript==
// @name Roblox Account Create
// @match https://www.roblox.com/
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @grant GM_addStyle
// ==/UserScript==
var _adj = [ 'Cool', 'Masked', 'Bloody', 'Lame' ];
var _animals = [ 'Hamster', 'Moose', 'Lama', 'Duck' ];
var _months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
var _username = _adj[ parseInt( Math.random( ) * _adj.length ) ], _pass = Math.random( ).toString( 36 ).substring( 2, 10 );
_username += _animals[ parseInt( Math.random( ) * _animals.length ) ];
_username += parseInt( Math.random( ) * 1000 );
var _dt_month = _months[ Math.floor( Math.random( ) * ( 12 ) + 0 ) ];
var _dt_day = Math.floor( Math.random( ) * ( 28 ) + 1 );
var _dt_year = Math.floor( Math.random( ) * ( 2005 - 1916 + 1 ) + 1916 );
window.addEventListener ("load", function load () {
setControl ('Username', _username );
setControl ('Password', _pass );
setControl ('PasswordConfirm', _pass );
setControl ('MonthDropdown', _dt_month );
setControl ('DayDropdown', _dt_day );
setControl ('YearDropdown', _dt_year );
$( '#FemaleButton' ).click( );
$( '#SignupButton' ).click( );
} );
function setControl (elemID, value) {
var zInput = $( '#' + elemID );
zInput.val( value );
var changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("change", true, true);
zInput[0].dispatchEvent (changeEvent);
}
请注意,我们使用了一个有效的 @grant
值,而不是 none
。这对于避免与页面的 javascript.
事实证明,有几个不同的事件会触发各种网站上的验证(输入、键入、更改)。这是我使用的功能,它似乎适用于所有网站(jquery、angularjs 或普通的旧 javascript):
function fireChangeEvents(element){
var changeEvent = null;
changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("input", true, true);
element.dispatchEvent (changeEvent);
console.debug('input event dispatched for element: '+element.id);
changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("keyup", true, true);
element.dispatchEvent (changeEvent);
console.debug('keyup event dispatched for element: '+element.id);
changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent ("change", true, true);
element.dispatchEvent (changeEvent);
console.debug('change event dispatched for element: '+element.id);
}
在这种情况下,我认为 jquery 应该有效:
fireChangeEvents(document.getElementById('Username'));
您可能需要小心,仅在值实际更改时才触发 "change" 事件。我在每个 "change" 事件上看到复选框上的一些草率代码切换 "valid" 而不是读取实际的复选框值。
注意:在 chrome 46.0.2490.71(portable_apps 版本)
上测试我无法使用此处的代码在 nextcloud 联系人应用程序(用 angular 编写)中设置联系人字段。这对我有用:
function setAngularInputValue (targetInput, newValue) {
targetInput.value = newValue;
const event = new Event('input', { bubbles: true });
targetInput.dispatchEvent(event);
}