[英]Automate form submission, on an AngularJS website, using Tampermonkey?
I'm trying to automate some form entry on a website that I do not have the source code to.我正在尝试在我没有源代码的网站上自动执行某些表单输入。 Finding the appropriate fields and filling them out with js and submitting the form programmatically is a simple enough task.
找到合适的字段并用 js 填写它们并以编程方式提交表单是一项足够简单的任务。 But the website is built in Angular and, when the form submit is clicked, all the validation flags for the input fields pop up as if none of the fields were filled out.
但是该网站是用 Angular 构建的,当单击表单提交时,输入字段的所有验证标志都会弹出,就好像没有填写任何字段一样。
Browsing several other posts, I came across the realization that I need to somehow either set the variable inside a scope, like this:浏览其他几篇文章,我意识到我需要以某种方式在范围内设置变量,如下所示:
$scope.$apply(function() {
$scope.fieldName = varname;
});
or to set the field to dirty, like this:或者将字段设置为脏,如下所示:
$scope.fieldname.$dirty = true;
Unfortunately, not having access to the code, I'm unsure of what the scope might be, or how to appropriately tell Angular that the fields on the form have been updated programmatically.不幸的是,无法访问代码,我不确定范围可能是什么,或者如何适当地告诉 Angular 表单上的字段已以编程方式更新。
Edit编辑
I'm using Roblox as an example for this error.我使用 Roblox 作为此错误的示例。
Different forms on the site such as the registration form (and forms behind the login) have validation on them, which throws the errors I mentioned.网站上的不同表单,例如注册表单(以及登录后的表单)都经过验证,这会引发我提到的错误。
Here's an example I made of trying to use the same logic as the login script on the register script:这是我尝试使用与注册脚本上的登录脚本相同的逻辑的示例:
// ==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( );
I have tried to add both the input and change events to my calls after changing the values, but there was no change in updating the validation to the values I added to the input fields.在更改值后,我尝试将输入和更改事件都添加到我的调用中,但是在将验证更新为我添加到输入字段的值时没有任何变化。 For example:
例如:
$( '#Username' ).val( _username ).trigger( 'input' ); // Also .trigger( 'change' )
You can test both of those script by adding them to Tampermonkey, and navigating to the ssl roblox homepage .您可以通过将它们添加到 Tampermonkey 并导航到ssl roblox 主页来测试这两个脚本。
The key point is that that Angular code (and similar JS) use change
events to trigger their validators.关键是 Angular 代码(和类似的 JS)使用
change
事件来触发它们的验证器。 So, just setting the value is not enough;所以,仅仅设置值是不够的; you must also send a change event.
您还必须发送更改事件。
So:所以:
.change()
, or .trigger()
, from a userscript that is not injected, seldom works..change()
或.trigger()
很少起作用。 Send a proper change event;@require
d jQuery (good), but used @grant none
(bad), your script was causing the page to crash and you would see various errors in the console.@require
d jQuery(好),但使用了@grant none
(坏),您的脚本导致页面崩溃,您会在控制台中看到各种错误。window.load
seems to be enough, but you may have to step up to something like waitForKeyElements()
if you should see more timing problems.window.load
似乎就足够了,但是如果您应该看到更多计时问题,您可能需要加强类似waitForKeyElements()
方法。$('#SignupButton').click ();
$('#SignupButton').click ();
可能存在其他计时问题$('#SignupButton').click ();
If so, that's outside the scope of this question. With that, the script becomes:这样,脚本就变成了:
// ==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);
}
Note that we use a valid @grant
value, other than none
.请注意,我们使用有效的
@grant
值,而不是none
。 That's crucial to avoid conflicts with the page's javascript.这对于避免与页面的 javascript 发生冲突至关重要。
it turns out there are several different events that trigger validation on various websites (input, keyup, change).事实证明,有几个不同的事件会触发各种网站上的验证(输入、键盘输入、更改)。 here is the function i use that seems to work on all websites (jquery, angularjs, or plain old 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);
}
in this specific case, i think this jquery should work:在这种特定情况下,我认为这个 jquery 应该可以工作:
fireChangeEvents(document.getElementById('Username'));
you might want to be careful to only fire the "change" event if the value was actually changed.如果值实际更改,您可能需要小心仅触发“更改”事件。 i have seen some sloppy code on checkboxes toggling "valid" on every "change" event rather than reading the actual checkbox value.
我看到复选框上的一些草率代码在每个“更改”事件上切换“有效”,而不是读取实际的复选框值。
note: tested on chrome 46.0.2490.71 (portable_apps edition)注意:在 chrome 46.0.2490.71(portable_apps 版)上测试
I was not able to get it work using the code here to set a contact field in the nextcloud contacts app (that is written in angular).我无法使用此处的代码在 nextcloud 联系人应用程序中设置联系人字段(以 angular 编写)使其工作。 This is what worked for me:
这对我有用:
function setAngularInputValue (targetInput, newValue) {
targetInput.value = newValue;
const event = new Event('input', { bubbles: true });
targetInput.dispatchEvent(event);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.