【问题标题】:Automate form submission, on an AngularJS website, using Tampermonkey?使用 Tampermonkey 在 AngularJS 网站上自动提交表单?
【发布时间】:2016-03-25 11:09:37
【问题描述】:

我正在尝试在我没有源代码的网站上自动输入一些表单。找到合适的字段并用 js 填写并以编程方式提交表单是一项非常简单的任务。但是该网站是用 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 来测试这两个脚本。

【问题讨论】:

  • 有测试用的网页网址就好了。
  • 我正在为其制作此脚本的站点是受 IP 限制的白名单。我确实有一些网站有篡改猴子自动登录到我的页面加载。其中一个网站也使用 angularjs,因此我遇到了同样的问题:Roblox
  • @BrockAdams,我已经更新了我的帖子以包含相关的测试 url 以及测试脚本来复制问题。

标签: javascript jquery angularjs greasemonkey tampermonkey


【解决方案1】:

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

所以:

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

这样,脚本就变成了:

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

【讨论】:

  • 我现在明白我的问题出在哪里了。我对 Angular 不太熟悉,但这很有效,你的回答让我理解了很多!
  • 旁注:我不必使用授权或导入 jquery 来调用 createEvent、initEvent 和 dispatchEventl,这解决了我的问题。虽然我确实认识到使用授权来隔离您的命名空间的价值。
【解决方案2】:

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

您可能需要小心,仅在值实际更改时才触发“更改”事件。我在复选框上看到了一些草率的代码,在每个“更改”事件上切换“有效”而不是读取实际的复选框值。

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

【讨论】:

  • 仍然有效,在 Firefox 70.0.1 上使用 ViolentMonkey 进行了测试。
【解决方案3】:

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

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

    targetInput.dispatchEvent(event);
}

【讨论】:

  • 哇!它完美无缺!非常优雅的解决方案!
猜你喜欢
  • 2018-01-15
  • 2012-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-12
  • 2012-02-03
  • 1970-01-01
  • 2016-01-09
相关资源
最近更新 更多