Logging in to Website with Excel-VBA - javascript

Thanks for taking a look at the question. I am trying to log into a website through VBA. This may have already been answered, but I'm having trouble finding something that works. I've done internet automation with VBA before. I've even used it to log into different sites before, but this one is giving me an issue. I've tried getElementByID, getElementByTagName, etc, but nothing seems to be able to populate the "loginName" and "password" text boxes.
The website is https://vfo.frontier.com/
What I found odd is that when I would go to inspect an element through GoogleChrome Browser it wouldn't take me to the text box I had selected.
Thanks so much in advance. Sorry for any errors, I'm still pretty new to VBA and this is my first post to the site.
The code I have now is below:
Sub FVFO()
Dim IE As InternetExplorerMedium
Dim uRl As String
Dim UserN As Object 'MSHTML.IHTMLElement
Dim PW As Object 'MSHTML.IHTMLElement
Set IE = New InternetExplorerMedium
uRl = "https://vfo.frontier.com/"
With IE
.navigate uRl
.Visible = True
End With
' loop until the page finishes loading
Do While IE.Busy
Loop
' enter username and password in textboxes
Set UserN = IE.document.getElementsByName("loginName")
If Not UserN Is Nothing Then
' fill in first element named "username", assumed to be the login name field
UserN.Value = "login name"
End If
Set PW = IE.document.getElementsByName("password")
' password
If Not PW Is Nothing Then
' fill in first element named "password", assumed to be the password field
PW.Value = "my Password"
End If
End Sub

GetElementsByName returns a collection of elements -- even if there is only one element, it is still a collection. So, you need to index it correctly. Assuming the first instance of such an element Name is the appropriate one:
UserN(0).Value = "login name"
And likewise:
PW(0).Value = "my password"
Results:
Tested in InternetExplorer.Application (I don't know what InternetExplorerMedium is...) using late-binding (although that should not matter):
Dim IE as Object
Set IE = CreateObject("InternetExplorer.Application")
The following also works using the getElementByID method, which returns a single element (because the id is unique):
Set UserN = IE.document.getElementByID("loginName")
If Not UserN Is Nothing Then
' fill in first element named "username", assumed to be the login name field
UserN.Value = "blargh"
End If
Set PW = IE.document.getElementByID("password")
' password
If Not PW Is Nothing Then
' fill in first element named "password", assumed to be the password field
PW.Value = "my Password"
End If

Related

Why Document properties body value is null in lotus notes?

Body content is null in document properties showing this sign ""[] instead of content.
Also messsage box lotus script is showing null with getItemValue("Body").
How to resolve this ?
Sub Click(Source As Button)
Dim s As NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim col As NotesDocumentCollection
Set s = New NotesSession
Set db = s.CurrentDatabase
Set col = db.UnprocessedDocuments
Print "Collection Size:"& col.Count
Set doc = col.GetFirstDocument
If doc.HasItem("Body") Then
While Not doc Is Nothing
Dim body As Variant
body = doc.GetItemValue("Body")
Msgbox (body(0))
Set doc = col.GetNextDocument(doc)
Wend
End If
End Sub
Because (usually) Body is a Rich Text field, and these fields are treated differently. See the NotesRichTextItem in the Designer Help.
Starting from your code:
Set s = New NotesSession
Set db = s.CurrentDatabase
Set col = db.UnprocessedDocuments
Print "Collection Size:"& col.Count
Set doc = col.GetFirstDocument
While Not doc Is Nothing
Dim body As Variant
If doc.HasItem("Body") Then
Set body = doc.GetFirstItem("Body") ' now body contains the richtext item'
Msgbox body.UnformattedText
End If
Set doc = col.GetNextDocument(doc)
Wend
Notes should convert the MIME item to rich text for you. If you want to deal with the MIME type, you have to use the NotesMimeHeader and NotesMimeEntity classes. See the Help database, especially the examples on these classes are interesting.
You cannot just reference a NotesRichtTextItem the same way you reference an ordinary NotesItem. A rich text field can contain graphics, tables, fonts, colors, and other things that are not text. It does not matter if it actually does contain those things; it is never a simple array of strings, so Body(0) is not defined. Look up the methods of the NotesRichTextItem class. You will find one called getUnformattedText which will return a simple text representation of the field value.
(There are options for getting the field value as HTML so that you get all the formatting tags, too, but only if the field is really stored as MIME instead of Notes rich text.)

I need help making a dynamic value attribute for html text fields

I'm looking for help with a very particular topic. I'm trying to change the default value inside a text field by using document.getElementById, however I'm not having very much luck.
The reason I have $name described below the script, is because the entire thing is inside a for loop to create a list of these names. When it calls the functions, it has no issue looking for the element ids because they're already created.
this code uses a mixture of php & html (you'll see a $dataarray[$i]['AI'], that's an auto-incrementing number used for pointing to the right info):
<?php
$name = "";
if($owner == 1)
{
$btnEdit = '<span id="btnEdit'.$dataarray[$i]['AI'].'"><button type="button" onclick="EditName('.$dataarray[$i]['AI'].', \''.$dataarray[$i]['lastname'].'\', \''.$dataarray[$i]['firstname'].'\');">Edit Name</button></span>';
?><script>
function EditName(logai, lastname, firstname)
{
window.stop();
var btnEditID = "btnEdit" + logai;
var editNameID = "editName" + logai;
document.getElementById(editNameID).innerHTML = '<input type="text" id="Lname" value="'+lastname+'" size="10">, <input type="text" id="Fname" value="' + firstname + '" size="10">';
document.getElementById(btnEditID).innerHTML = '<button type="button" onclick="SubmitName('+logai+', \''+lastname+'\', \''+firstname+'\');">Submit Name</button> <button type="button" onclick="CancelEdit(\''+btnEditID+'\', \''+editNameID+'\', '+logai+', \''+lastname+'\', \''+firstname+'\');">Cancel Edit</button><br>';
}
function SubmitName(logai, lastname, firstname)
{
// old: lastname = document.getElementById(Lname).value;
lastname = Lname.value;
// old: firstname = document.getElementById(Fname).value;
firstname = Fname.value;
// Don't worry about the ajax code, I made sure it works:
// it just updates the record at the given incrementing number
$.ajax({ type:'POST',
url:'/bin/editPersonName.php',
data:{ai:logai, fname:firstname, lname:lastname},
success:function(data2){
console.log(data2);
}
});
// location.reload();
}
function CancelEdit(btnEditID, editNameID, logai, lastname, firstname)
{
document.getElementById(btnEditID).innerHTML = '<button type="button" onclick="EditName('+logai+', \''+lastname+'\', \''+firstname+'\');">Edit Name</button>';
document.getElementById(editNameID).innerHTML = '<input type="text" name="Name" value="'+lastname+', '+firstname+'" readonly>';
// There is no way to turn refresh back on, so we simply have to reload the page
location.reload();
}
</script><?php
$name = '<span id="editName'.$dataarray[$i]['AI'].'"><input type="text" name="Name" value="'.$dataarray[$i]['lastname'].', '.$dataarray[$i]['firstname'].'" readonly></span>';
}
The order of progression goes as follows:
1) See the name pop up in a name text field, with an edit button next to it
2) Notice name is spelled wrong, so click the edit button
3) Edit button clicked, it turns into 2 buttons (a submit button, and a Cancel button) while the
name field turns into two text fields separated by a comma (a lastname, firstname orientation)
4) Type into the text fields what changes you want, then click the Submit button
5) Submit button takes the new text from the two text fields and updates the name at the given
ai location (this is where I have the issue; it doesn't get the new stuff typed inside the lastname, firstname fields)
6) Page reloads to do a few things: update the information filled in, reset the field layout, and "turn
on" the page's auto-refresh (I have location.reload() commented to see the message it returns
upon ajax; which is just a pass/fail message)
(note: I apologize if there's a paragraph placed in the wrong location, I'm in a bit of a time crunch and I didn't have enough time to check for literature sensibility this morning)
The document.getElementById() function's parameter must be a string but you provide undefined variables to it.
lastname = document.getElementById('Lname').value;
firstname = document.getElementById('Fname').value;
Update: After typing document.getElementById(Lname) and Lname into the dev tools' console, I had an idea: What would happen if I just set lastname & firstname to Lname.value & Fname.value? What happens is that it fixes my issue (my coworker was the one who made me think of it, as he wanted to see what typing the getElementById in console would do). It may have been a scope issue that was causing it, but this is definitely a step people should take from my mistake:
If the Element is coming back as null when searched by document, try looking at the value in your browser's console. If something doesn't add up to you, try going one step inwards.

How do I get VBA to submit a javascript form?

I am not sure if I am referencing the button correctly. I keep on getting:
Run-time error '438': Object doesn't support this property or method.
This is what my code looks like at the moment:
Sub russInd()
Dim oButton As Object, HTMLdoc As Object
Dim sht1 As Worksheet, myURL As String
Set ie = CreateObject("InternetExplorer.Application")
Set sht1 = Worksheets("Day 1")
myURL = sht1.Cells(32, 2).Value
ie.navigate myURL
ie.Visible = True
Do Until ie.ReadyState = 4
DoEvents
Loop
'Locate The correct forms and buttons
Set HTMLdoc = ie.document
Set oButton = HTMLdoc.querySelectorAll("a[href='javascript:submitForm(document.forms[0].action);']")
'Check All Checkboxes
HTMLdoc.getElementByID("chkAll").Click
oButton.Click
End Sub
The webpage I am using is:
https://indexcalculator.ftserussell.com/
Here is the webpage code:
I need to click the next button, I did try using
.getElementByID("CtlNavigation_lblControl")
To click the button, however that just skipped over the command, I guess it clicked nothing. Thanks!
querySelectorAll returns a nodelist. You likely want querySelector
Try
HTMLdoc.getElementById("CtlNavigation_lblControl").querySelector("a").Click
or
HTMLdoc.querySelector("CtlNavigation_lblControl a").Click
Set your selector to this: (It's saying look for any image in a parent A element.)
Set oButton = HTMLdoc.querySelectorAll("a > img")
Here is the full code with the modification:
Sub russInd()
Dim oButton As Object, HTMLdoc As Object
Dim sht1 As Worksheet, myURL As String
Set ie = CreateObject("InternetExplorer.Application")
Set sht1 = Worksheets("Day 1")
myURL = sht1.Cells(32, 2).Value
ie.navigate myURL
ie.Visible = True
Do Until ie.ReadyState = 4
DoEvents
Loop
'Locate The correct forms and buttons
Set HTMLdoc = ie.document
Set oButton = HTMLdoc.querySelectorAll("a > img")
'Check All Checkboxes
HTMLdoc.getElementByID("chkAll").Click
oButton.Click
End Sub
Use the following selector as it works across all steps. The number of child a elements within the parent with id Ctlnavigation2_lblControl changes so the following is a robust way to always get what you want across pages.
HTMLdoc.querySelector("#Ctlnavigation2_lblControl [href*=action]").Click
Your error, as partially correct in comments, is that you are trying to use a method of certain node types e.g. a tag element on a nodeList (which is what querySelectorAll returns). It does NOT return a collection. That is a very important distinction in VBA. If you try to For Each, as you would with a collection, over that nodeList Excel will crash.

Getting the content of a table that being hidden by an onclick button javascript using JSoup

I am creating an web scraping for personal use in gaming.
This is the website i am going to scrape: http://forum.toribash.com/clan_war.php?clanid=139
And i want to count the frequency of the name that appears on the "shows detail".
I have read this Get content from javascript onClick hyperlink without knowing that if this actually what i am searching for. I have a doubt that this is not what i am searching for, but regardless i have not try the answer of that questions since i have no idea on how to make this https://stackoverflow.com/a/12268561/10467473 fit to what i want.
BufferedReader month = new BufferedReader(new InputStreamReader(System.in));
String mth = month.readLine();
//Accessing the website
Document docs = Jsoup.connect("http://forum.toribash.com/clan_war.php?clanid=139").get();
//Taking every entry of war history
Elements collection = docs.getElementsByClass("war_history_entry");
//Itterate every collection
for(Element e : collection){
//if the info is on the exact month that are being searched we will use the e
if(e.getElementsByClass("war_info").text().split(" ")[1].equalsIgnoreCase(mth)){
//supposedly it holds every element that has player as it class inside of the button onclick
//But it doesn't work
Elements cek = e.getElementsByClass("player");
for(Element c : cek){
System.out.println(c.text());
}
}
For now i am expecting to get at least the name on show details table
Kaito
Chax
Draku
and so on
This page doesn't contain the information you want to scrape. Results are loaded by AJAX (Javascript) after the button is clicked.
You can use your web browser's debugger to look on the Network tab to see what happens when you click the button.
Clicking a button
<button id="buttonwarid19557" ... >
loads a table from URL:
http://forum.toribash.com/clan_war_ajax.php?warid=19557&clanid=139
Notice the same id number.
What you have to do is to get the id from every button, then GET another document for each of these buttons and parse it one by one. That's what your web browser does anyway.
BufferedReader month = new BufferedReader(new InputStreamReader(System.in));
String mth = month.readLine();
//Accessing the website
Document docs = Jsoup.connect("http://forum.toribash.com/clan_war.php?clanid=139").get();
//Taking every entry of war history
Elements collection = docs.getElementsByClass("war_history_entry");
//Itterate every collection
for(Element e : collection){
//if the info is on the exact month that are being searched we will use the e
if(e.getElementsByClass("war_info").text().split(" ")[1].equalsIgnoreCase(mth)){
// selecting button
Element button = e.selectFirst("button");
// getting warid from button id
String buttonId = button.attr("id");
// removing text because we need only number
String warId = buttonId.replace("buttonwarid", "");
System.out.println("downloading results for " + e.getElementsByClass("war_info").text());
// downloading and parsing subpage containing table with info about single war
// adding referrer to make the request look more like it comes from the real web browser to avoid possible hotlinking protection
Document table = Jsoup.connect("http://forum.toribash.com/clan_war_ajax.php?warid=" + warId + "&clanid=139").referrer("http://forum.toribash.com/clan_war.php?clanid=139").get();
// get every <td class="player"> ... </td>
Elements players = table.select(".player");
for(Element player : players){
System.out.println(player.text());
}
}
}

Prompt user to replace certain parts of text in a string

I have a program that allows a user to type JavaScript in a textbox, and it executes in an HTML viewer or iframe. There is a drop down with options such as "Insert Image", which inserts
var $'Image Name' = document.createElement('img');
$'Image Name'.src = $'Image URL';
$'Image Name'.style.position = 'absolute';
document.body.appendChild($'Image Name');
into the textbox. I want the user to select the option "Insert Image", and have a dialog go through each $'', and ask for something to replace them with, so for the first $'Image Name', prompt the user for a variable name, and then replace("$'Image Name'", userText) so all the $'Image Name's get replaced and the user isn't prompted for the same one again. Any ideas? I have this replace:
replace(/^\$\"|\'.$\"|\'/gi, function ($string) { return prompt($string);});
but it matches the quotes, not the text inside the quotes, and I don't even know regex, if you can solve the regex, I can figure out the rest.
I guess you want something like this:
replace(/\$'([^']+)'/g, function (s, contents) { return prompt(contents); });
though I should mention that this will misbehave if a single-quoted string happens to end with a dollar-sign, or if a double-quoted string happens to contain $', or whatnot; do you need to be able to handle these sorts of cases? (It's not obvious from your question whether you completely control the contents of the textarea, or whether it's something your users might be editing.)

Categories

Resources