使用Tampermonkey在AngularJS网站上自动提交表单?

时间:2015-12-18 17:18:12

标签: javascript jquery angularjs greasemonkey tampermonkey

我试图在我没有源代码的网站上自动化某些表单条目。找到适当的字段并用j填充它们并以编程方式提交表单是一项非常简单的任务。但是该网站是在Angular中构建的,当单击表单提交时,输出字段的所有验证标志都会弹出,就像没有填写任何字段一样。

浏览其他几篇帖子时,我发现我需要以某种方式将变量设置在范围内,如下所示:

$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来测试这两个脚本。

3 个答案:

答案 0 :(得分:6)

关键是Angular代码(和类似的JS)使用change事件来触发它们的验证器。所以,仅仅设置值是不够的;你还必须发送一个改变事件。

所以:

  1. 设置值。
  2. 发送更改活动。对于Greasemonkey / Tampermonkey脚本,您必须注意此部分的沙箱和jQuery冲突。
    从未注入的用户脚本中使用 jQuery <{em} .change().trigger(),很少有效。发送适当的变更事件;见下文。
  3. 由于@require j jQuery(不错),但使用@grant none(错误),您的脚本导致页面崩溃,您会在控制台中看到各种错误。
  4. 脚本具有竞争条件,并且在输入准备好之前经常触发。等待window.load似乎已经足够了,但如果您发现更多时间问题,则可能需要加强waitForKeyElements()之类的工作。
  5. $('#SignupButton').click ();可能存在其他时间问题。如果有,这超出了此问题的范围。
  6. 请勿使用此知识违反任何网站的服务条款。 (如适用)
  7. 这样,脚本就变成了:

    // ==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冲突至关重要。

答案 1 :(得分:1)

事实证明,有几个不同的事件会触发各种网站(输入,密钥,更改)的验证。这是我使用的功能似乎适用于所有网站(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'));

你可能要小心,只能解雇&#34;改变&#34;如果值实际更改,则为event。我在复选框上看到了一些草率的代码切换&#34;有效&#34;每一次&#34;变化&#34;事件而不是读取实际的复选框值。

注意:在chrome 46.0.2490.71(portable_apps edition)上测试

答案 2 :(得分:0)

我无法使用此处的代码在nextcloud联系人应用程序(以角度编写)中设置联系人字段来使其工作。这对我有用:

function setAngularInputValue (targetInput, newValue) {
    targetInput.value = newValue;
    const event       = new Event('input', { bubbles: true });

    targetInput.dispatchEvent(event);
}