Create alert in Google Alert using PhantomJS - javascript

If you go to Google Alert website while you are not login with your Google Account you would have a chance of creating an alert send to your Yahoo account for example.
I am going create an alert using PhantomJS. Then I would need to click on the CREATE ALERT button. I need to do that using JavaScript. But it seems that PhantomJS cannot click on this button!
I have even tried to click on this button through Google Console but I could not.
I have used three different ways for clicking on the button which nothing works. Can someone help me to click on the CREATE ALERT button?
javascript:if(!window.jQuery||confirm('Overwrite\x20current\x20version?\x20v'+jQuery.fn.jquery))(function(d,s){s=d.createElement('script');s.src='https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.js';(d.head||d.documentElement).appendChild(s)})(document);
var inputOne = document.getElementsByTagName('input')[0];
inputOne.value = "testAlert";
var inputTwo = document.getElementsByTagName('input')[1];
inputTwo.value = "test#yahoo.com";
var button = document.getElementById('create_alert');
//1.
//button.click();
//2.
//$(button).trigger('click');
//$(button).trigger('change');
//3.
var event = document.createEvent("MouseEvents");
event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
button.dispatchEvent(event);
And I am using following code in PhantomJS
phantom.injectJs("functions/jquery.js");
var page = require('webpage').create();
var load, contoroller;
var numOfActions = 1;
var clicked = false;
var initialURL = "https://www.google.com/alerts";
page.open(initialURL, function(status) {
load = true;
});
page.onLoadFinished = function(status)
{
clearInterval(contoroller);
if (clicked)
{
console.log("The status of loading the page is " + status + "\n");
page.render("SCREENSHOTS/page_" + numOfActions + ".png");
numOfActions += 1;
phantom.exit();
}
else
{
contoroller = setInterval(function () {
if (load)
{
console.log("The status of loading the page is " + status + "\n");
page.render("SCREENSHOTS/page_" + numOfActions + ".png");
numOfActions += 1;
load = false;
enterQuery("test");
}
else
{
console.log("The status of loading the page is " + status + "\n");
page.render("SCREENSHOTS/page_" + numOfActions + ".png");
numOfActions += 1;
page.evaluate(function(){
var input = document.getElementsByTagName('input')[1];
input.value = "test#test.com";
})
click();
}
}, 5000);
}
}
function enterQuery(query)
{
page.injectJs("functions/jquery.js");
page.evaluate(function(query)
{
var box = document.getElementsByTagName('input')[0];
box.value = query;
//$(box).keypress();
}, query);
}
function click()
{
clicked = true;
clearInterval(contoroller);
var but = page.evaluate(function(){
var button = document.getElementById('create_alert');
//var event = document.createEvent("MouseEvents");
//event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
//button.dispatchEvent(event);
return button;
})
page.sendEvent('click', but);
window.setTimeout(function () {
console.log("The status of loading the page is " + status + "\n");
page.render("SCREENSHOTS/page_" + numOfActions + ".png");
numOfActions += 1;
phantom.exit();
}, 5000);
}
It seems that I need to first hover the mouse on the button. When you hover the mouse you will see that the class attribute of the element changes. I have tried $(button).trigger('mouseover') but after that the class attribute did not change. How can I trigger mouseover on this element?

There are two problems with your code: typing and clicking.
When you set the value of an input field directly, none of the input event handlers are called. You could use the native page.sendEvent("keypress", keys) which types keys as if a user would type them, so all event handlers will be triggered. Since the function doesn't know where to type to, you need to focus on the element first:
page.evaluate(function(selector){
document.querySelector(selector).focus();
}, selector);
page.sendEvent("keypress", query);
You can solve the clicking also with page.sendEvent("click", posx, posy). Now the challenge becomes to find out the position of the elements on the page. This answer provides a jQuery way of solving this:
page.injectJs("jquery.min.js");
var rect = page.evaluate(function(selector) {
return $(selector)[0].getBoundingClientRect();
}, selector);
page.sendEvent('click', rect.left + rect.width / 2, rect.top + rect.height / 2);
This is your full script that works as expected:
var page = require('webpage').create();
var load, contoroller;
var numOfActions = 1;
var clicked = false;
var initialURL = "https://www.google.com/alerts";
page.open(initialURL, function(status) {
load = true;
});
page.onLoadFinished = function(status)
{
clearInterval(contoroller);
if (clicked)
{
console.log("1| The status of loading the page is " + status + "\n");
page.render("SCREENSHOT/page_" + numOfActions + ".png");
numOfActions += 1;
phantom.exit();
}
else
{
contoroller = setInterval(function () {
if (load)
{
console.log("2| The status of loading the page is " + status + "\n");
page.render("SCREENSHOT/page_" + numOfActions + ".png");
numOfActions += 1;
load = false;
enter("input", "test"); // very first input
}
else
{
console.log("3| The status of loading the page is " + status + "\n");
page.render("SCREENSHOT/page_" + numOfActions + ".png");
numOfActions += 1;
enter("input.email_input", "test#test.com");
setTimeout(function(){
click("#create_alert");
}, 500);
}
}, 5000);
}
}
function enter(selector, query)
{
page.evaluate(function(selector){
document.querySelector(selector).focus();
}, selector);
page.sendEvent("keypress", query);
}
function click(selector)
{
clicked = true;
clearInterval(contoroller);
page.injectJs("functions/jquery.js");
var rect = page.evaluate(function(selector) {
return $(selector)[0].getBoundingClientRect();
}, selector);
page.sendEvent('click', rect.left + rect.width / 2, rect.top + rect.height / 2);
window.setTimeout(function () {
console.log("4| The status of loading the page is " + status + "\n");
page.render("SCREENSHOT/page_" + numOfActions + ".png");
numOfActions += 1;
phantom.exit();
}, 5000);
}

Related

Automate Login / Surf and Download File on criteria using Phantomjs

I've been trying to do this since a long time.
[PHANTOMJS VERSION] => 2.1.1
My goal is to log in a portal, go to different menu after being logged, insert parameters to research available file, download file if not downloaded yet.
Problem is that I can login to the portal and reach the index page but when I click on the tag "a" which is the one button that bring me to the new form to fill for searching file, it bring me back to loginpage ... Dunno why that happend. If I use this script in chrome dev it works fine ...
LOGIN SUCCESFUL
REDIRECTED TO LOGIN PAGE
This is my code:
<pre><code>var page = require('webpage').create();
var system= require('system');
var loadInProgress = false;
var testindex = 0;
var address;
var pos;
var stringa;
// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.onError = function(msg, trace) {
var msgStack = ['ERROR: ' + msg];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function(t) {
msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : ''));
});
}
console.error(msgStack.join('\n'));
};
page.onAlert = function(msg) {
console.log('alert!!> ' + msg);
};
page.onLoadStarted = function() {
loadInProgress = true;
console.log("CARICAMENTO PAGINA INIZIATO"); //*Page started loading*
};
page.onLoadFinished = function(status) {
loadInProgress = false;
if (status !== 'success') {
console.log('Caricamento pagina fallito !'); //*Page failed to load*
phantom.exit();
} else {
console.log("CARICAMENTO PAGINA COMPLETATO"); //*Page loading complete*
page.render("foto" + testindex + ".png");//*Screen Capture*
console.log("Foto effettuata");
var sitoattuale= page.evaluate(function(){
return window.location.href;
});
console.log(sitoattuale);
}
};
var steps = [
function() {
page.open(system.args[1]);
},
function() {
page.evaluate(function() {
//*insert username and password and click the button to submit the form*
document.getElementById("twsTemplate_Content1_twsModule_txtUser").value="MYUSERNAME";
document.getElementById("twsTemplate_Content1_twsModule_txtPSW").value="MYPASSWORD";
document.getElementById("twsTemplate_Content1_twsModule_btnLogin").click();
});
//*Capture inserted credentials*
page.render("credenziali.png")
},
function() {
page.evaluate(function(){
var a=document.getElementById("twsTemplate_Header1_Mainmenu2_aspMainMenun16Items");
var b= a.getElementsByTagName("a");
var c= b[0];
c.click();
});
//*Capture click of the button that brings me to the form where I ve to insert parameters for the search*
page.render("Cliccato_ricerca.png")
},
function() {
//*I capture the screen as I should be to the form page but it caputre the login page unfilled*
page.render("ramomisura.png")
console.log("stouscendo");
}
];interval = setInterval(function() {
if (!loadInProgress && typeof steps[testindex] == "function") {
if (testindex==0){
console.log("Fase " + (testindex+1) + " : Avvio portale");
}else{
if(testindex==1){
console.log("Fase " + (testindex+1) + " : Loing in corso ...");
}else{
if(testindex==2){
console.log("Fase " + (testindex+1) + " : Tentativo di navigazione al ramo misure ...")
}else{
console.log("Fase " + (testindex+1) + " : Termine Programma");
}
}
}
steps[testindex]();
testindex++;
}
if (typeof steps[testindex] != "function") {
console.log("Programma Terminato");
phantom.exit();
}
}, 100)
</code></pre>

Can I save multiple JavaScript Object methods as a variable?

I am writing an extension for a text-editor (Brackets) that can generate HTML and append libraries automatically in the HTML.
I have an Object called 'choice'.
This modal requests the users input:
choice grabs the user's input by defining methods on choice
partial JS here:
var choice = new Object();
choice.language = function () {
//Buid HTML top 'head'
var htmlTop = "<!DOCTYPE html>" + "<html>" + "<head lang='";
//Grab Selected Language Type
var languageChoice = document.getElementById("languages").value;
//Determine what Selected Language type is and complete HTML 'head'
if (languageChoice === "english") {
languageChoice = "en";
return htmlTop + languageChoice + "'>";
} else if (languageChoice === "german") {
languageChoice = "de";
return htmlTop + languageChoice + "'>";
} else if (languageChoice === "spanish") {
languageChoice = "es";
return htmlTop + languageChoice + "'>";
} else if (languageChoice === "french") {
languageChoice = "fr";
return htmlTop + languageChoice + "'>";
} else if (languageChoice === "italian") {
languageChoice = "it";
return htmlTop + languageChoice + "'>";
} else if (languageChoice === "chinese") {
languageChoice = "zh-cn";
return htmlTop + languageChoice + "'>";
}
}; //end choice.language
choice.charset = function () {
//Build meta and the rest of the 'head tag'
var htmlCharset_Beginning = "<meta charset='";
var htmlCharset_End = "'>" + "<title> -Insert Title- </title>" + "<!-- Insert CSS links below -->" + "</head>" + "<body>";
var charsetChoice = document.getElementById("charset").value;
if (charsetChoice === "utf8") {
charsetChoice = "UTF-8";
return htmlCharset_Beginning + charsetChoice + htmlCharset_End;
} else {
charsetChoice = "UTF-16";
return htmlCharset_Beginning + charsetChoice + htmlCharset_End;
}
}; // end choice.charset
choice.doctype = function () {
var doctypeChoice = document.getElementById("doctype").value;
return doctypeChoice;
}; // end doctype
choice.libraries = function () {
var checkedBoxes = getCheckedBoxes("lib_checkboxes");
checkedBoxes.forEach(function(item){
var scripts =+ $(item).data('script');
});//End forEach
var bottomHTML = scripts + "</body>" + "</html>";
return bottomHTML;
}; //End choice.libraries
var chosenTemplate = function(){
var template = choice.language() + choice.charset() + choice.libraries();
// insert html into file, this will overwrite whatever content happens to be there already
EditorManager.getCurrentFullEditor()._codeMirror.setValue(template);
// automatically close the modal window
$('#templates_modalBtn').click();
};
//Get checkedBoxes function
// Pass the checkbox name to the function
function getCheckedBoxes(chkboxName) {
var checkboxes = document.getElementsByName(chkboxName);
var checkboxesChecked = [];
// loop over them all
for (var i = 0; i < checkboxes.length; i++) {
// And stick the checked ones onto an array...
if (checkboxes[i].checked) {
checkboxesChecked.push(checkboxes[i]);
}
}
// Return the array if it is non-empty, or null
return checkboxesChecked.length > 0 ? checkboxesChecked : null;
}
} // End action();
//JEFF STOP CODING HERE
// Register the commands and insert in the File menu
CommandManager.register(Strings.MENU_COMMAND, 'templates', action);
var menu = Menus.getMenu(Menus.AppMenuBar.EDIT_MENU);
menu.addMenuDivider();
menu.addMenuItem('templates');
}); //end define;
QUESTION:
Can I save multiple methods (each method returns a string) as a variable?
Example here:
var chosenTemplate = function(){
var template = choice.language() + choice.charset() + choice.libraries();
// insert html into file, this will overwrite whatever content happens to be there already
EditorManager.getCurrentFullEditor()._codeMirror.setValue(template);
// automatically close the modal window
$('#templates_modalBtn').click();
};
My code is loading with no errors, but its not executing at all so I am trying to debug and figure out what is going wrong...
Before you realize the function 'chosenTemplate', you should check whether the document stream of the page has already downloaded. If it not, you may not be able to get the value of the widget (empty).

Javascript Parameters Function on Many Events

I'm trying to implement hammer.js to swipe pages (like a book) and I did it. The problem is that this works
var idHammer1 = document.getElementById("pageHoja1")
//var hammertime = new Hammer(myElement, hammerOptionsPan);
var objHammer1 = new Hammer(idHammer1);
objHammer1.on('panleft panright', function(ev)
{
//DBLog("obj1 - gSceneActual Antes: " + gSceneActual + " // X: " + ev.center.x + " Y: " + ev.center.y);
if (ev.type==='panleft')
{
if (!(gSceneActual===2))
{
gSceneActual = 2;
$(":mobile-pagecontainer").pagecontainer("change", "#pageHoja2", { transition: "slide", reverse: false});
}
}
else if (ev.type==='panright')
{
}
});
but this doesn't:
var fSwipe1 = function(ev)
{
//DBLog("obj1 - gSceneActual Antes: " + gSceneActual + " // X: " + ev.center.x + " Y: " + ev.center.y);
if (ev.type==='panleft')
{
if (!(gSceneActual===2))
{
gSceneActual = 2;
$(":mobile-pagecontainer").pagecontainer("change", "#pageHoja2", { transition: "slide", reverse: false});
}
}
else if (ev.type==='panright')
{
}
}
var idHammer1 = document.getElementById("pageHoja1")
//var hammertime = new Hammer(myElement, hammerOptionsPan);
var objHammer1 = new Hammer(idHammer1);
objHammer1.on('panleft panright', fSwipe1(ev))
and this also don't work
function fSwipe1(ev)
{
//DBLog("obj1 - gSceneActual Antes: " + gSceneActual + " // X: " + ev.center.x + " Y: " + ev.center.y);
if (ev.type==='panleft')
{
if (!(gSceneActual===2))
{
gSceneActual = 2;
$(":mobile-pagecontainer").pagecontainer("change", "#pageHoja2", { transition: "slide", reverse: false});
}
}
else if (ev.type==='panright')
{
}
}
and since I need to add this event to many pages (variable #) I cant hardcode it... How can I make it variable inside a cycle?
Thanks!
Ah, without knowing the extent of the errors, I do see:
objHammer1.on('panleft panright', fSwipe1(ev));
Here, you are rendering the function automatically, but what you actually want is to use a closure so that the function does not get rendered until the event gets hit. I'm not sure what ev represents, but if it is the event object, then this should work:
objHammer1.on('panleft panright', fSwipe1);
Where all you are doing is passing in the function that you want to be the callback and the even will automatically call this function and pass the event object as the first parameter.
A few other things that I notice:
make sure that you include the javascript library for Hammer
Make sure that gSceneActual is defined before it is evaluated at gSceneActual===2
Make sure that jQuery library is included

How can I prevent my javascript from polling websites too fast?

I made this website quite a while ago for the purpose of grabbing random puu.sh images and displaying them. Also a warning, the content this site shows is user generated, and I can not guarantee it is SFW.
https://dl.dropboxusercontent.com/s/dlb1uke5udz8kwy/index.html
I just started looking at it again, and it appears it has some serious bugs with the systems it uses to gather content. How can I change my javascript so that it doesn't spam out puu.sh, and make it refuse connections?
Here is the code:
var currentThumb = 0;
function getImgUrl()
{
var text = (Math.round(Math.random() * 9)).toString();
//var text = '3T';
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for(var i=0; i < 4; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return 'http://puu.sh/' + text;
}
function open_in_new_tab(url)
{
var win=window.open(url, '_blank');
win.focus();
}
function getImages()
{
//var width = window.innerWidth;
var images = 10;
for(var i = 0;i < images;i++)
{
var url = getImgUrl();
document.getElementById('thumbs').innerHTML += '<img class="thumb" id="thumb' + i + '" src=' + url + '>';
if(i == 0)
{
document.getElementById('fullimage').innerHTML = '<img id="big" src=' + url + '>';
$('#thumb' + currentThumb).css('border','2px solid white');
}
}
}
function refreshImages()
{
var images = 10;
for(var i = 0;i < images;i++)
{
var url = getImgUrl();
$('#thumb' + i).attr('src',url);
}
$('img').css('border','');
$('#thumb' + currentThumb).css('border','2px solid white');
}
function resize()
{
var width = $(window).width();
var height = $(window).height();
$('#fullimage img').css('max-width',width);
$('#fullimage img').css('max-height',height - 87);
}
function setBig()
{
$('#big').attr('src',($('#thumb' + currentThumb).attr('src')));
$('img').css('border','');
$('#thumb' + currentThumb).css('border','2px solid white');
resize();
}
getImages();
$('img').error(function() {
$(this).attr('src',getImgUrl());
setBig();
});
$('#thumbs img').click(function() {
$('#fullimage').html('<img id="big" src=' + $(this).attr('src') + '>');
currentThumb = parseInt($(this).attr("id").match(/\d+/));
$('img').css('border','');
$(this).css('border','2px solid white');
resize();
});
$('#fullimage').click(function() {
open_in_new_tab($('#fullimage img').attr('src'));
});
$(window).resize(function() {
resize();
});
$(document).ready(function() {
resize();
});
The problem most likely lies in
$('img').error(function() {
$(this).attr('src',getImgUrl());
setBig();
});
Your main problem seems to be that you are spamming the servers when you hit a 404 because of the error handler. Try something like
$('img').error(function() {
var _this = this;
setTimeout(function () {
$(_this).attr('src',getImgUrl());
setBig();
}, 500); // Whatever timeout is good not to spam
});
Untested, but try this new getImages() function (replace the old one)
function getImages(images)
{
if (!images) {
document.getElementById('fullimage').innerHTML = '<img id="big" src=' + url + '>';
$('#thumb' + currentThumb).css('border','2px solid white');
images = 1;
}
document.getElementById('thumbs').innerHTML += '<img class="thumb" id="thumb' + i + '" src=' + url + '>';
images++;
if (images < 10) {
setTimeout(function() { getImages(images); }, 25);
}
}
It will be called 9 times, but the first time it should do what you were doing at i = 0 and 1; It will be fired every 25ms regardless of whether images have loaded yet or not. Increase that number (25) to slow it down.

pagination with AJAX url

Im beginner in AJAX & JS so please bear with me.
I use this AJAX for the pagination :
$(function () {
var keyword = window.localStorage.getItem("keyword");
//pagination
var limit = 3;
var page = 0;
var offset = 0;
$("#btnLoad").on('click', function () {
page++;
if (page != 0)
offset = (page - 1) * limit;
$.ajax({
url: "http://localhost/jwmws/index.php/jwm/search/msmall/" + keyword + "/" + limit + "/" + offset, //This is the current doc
type: "GET",
error: function (jq, st, err) {
alert(st + " : " + err);
},
success: function (result) {
alert("offset=" + offset + " page =" + page);
//generate search result
$('#search').append('<p style="float:left;">Search for : ' + keyword + '</p>' + '<br/>' + '<p>Found ' + result.length + ' results</p>');
if (result.length == 0) {
//temp
alert("not found");
} else {
for (var i = 0; i < result.length; i++) {
//generate <li>
$('#list').append('<li class="box"><img class="picture" src="images/HotPromo/tagPhoto1.png"/><p class="name"><b>Name</b></p><p class="address">Address</p><p class="hidden"></p></li>');
}
var i = 0;
$(".box").each(function () {
var name, address, picture, id = "";
if (i < result.length) {
name = result[i].name;
address = result[i].address;
picture = result[i].boxpicture;
id = result[i].mallid;
}
$(this).find(".name").html(name);
$(this).find(".address").html(address);
$(this).find(".picture").attr("src", picture);
$(this).find(".hidden").html(id);
i++;
});
$(".box").click(function () {
//alert($('.hidden', this).html());
window.localStorage.setItem("id", $('.hidden', this).html());
$("#pagePort").load("pages/MallDetail.html", function () {});
});
}
}
});
}).trigger('click');
});
Please notice that i use the variables for pagination in the url:. I tried to alert the page and offset variable, and its working fine.
However, the AJAX only working for the first page (when page load). The rest is not working even though the page and offset variable's value is true.
Theres no warning/error in console. The data just not shown.
Any help is appreciated, Thanks :D
It is a bit hard to debug your code when the whole HTML is missing.
Could you put your code into JSFiddle, both HTML and JS.

Categories