Getting VBA to Reference and Accept 2 Word Source Code (HTML) - html

I'd like to have someone fill out specific cells in a spread sheet, and have those cells be uploaded to a webpage when the macro is run. Now, I've taken the code from this webpage:
http://www.familycomputerclub.com/how-to-login-automatically-into-website-using-excel-vba.html
and have altered it to do what I want. It works for the source code that only has a one word name, though:
<td align=right class=lbl>Model </td>
<td align=left><input type=text size=20 name="xModel" value=""></td>
</tr>
It does not work for source code that has a two letter name:
<td align=right class=lbl>Serial Number </td>
<td align=left><input type=text size=20 name="xSerial Number" value=""></td>
</tr>
The code I have is as follows:
Dim HTMLDoc As HTMLDocument
Dim MyBrowser As InternetExplorer
Sub MyTruck()
Dim MyHTML_Element As IHTMLElement
Dim MyURL As String
On Error GoTo Err_Clear
MyURL = "http://website.com"
Set MyBrowser = New InternetExplorer
MyBrowser.Silent = True
MyBrowser.navigate MyURL
MyBrowser.Visible = True
Do
Loop Until MyBrowser.readyState = READYSTATE_COMPLETE
Set HTMLDoc = MyBrowser.document
HTMLDoc.all.Name.Value = "John Miller" 'Enter your name here
HTMLDoc.all.Email.Value = "John.Miller#gmail.com" 'Enter your email here
HTMLDoc.all.xDepartment.Value = "WHSE" 'Enter Department Here
HTMLDoc.all.XPhone Number.Value = "6035554895" 'Enter Phone Number Here
HTMLDoc.all.xEquipment Number.Value = "544" 'Enter Equipment Number Here
HTMLDoc.all.xModel.Value = "CAT" 'Enter Model Here
HTMLDoc.all.xSerial Number.Value = "M711894xvJq" 'Enter Serial Number Here
For Each MyHTML_Element In HTMLDoc.getElementsByTagName("input")
If MyHTML_Element.Type = "submit" Then MyHTML_Element.Click: Exit For
Next
Err_Clear:
If Err <> 0 Then
Err.Clear
Resume Next
End If
End Sub
In this shortened version of the code(I eliminated some of the HTMLDoc.All code because I was trying to save space), everything works except for the phone number, equipment number, and serial number. If there is anyway to make this work with two word source codes, that would be appreciated. I've tried using "", underscores, and taking out spaces completely. I tried to dim the name to something with spaces, but I'm not sure that I did it right. Thanks in advance!!!
I also can't alter the source code, the website is a corporate website.

Related

Website scraping: website search box has no value

I am trying to crosscheck a large body of data with a specific website (https://icis.corp.delaware.gov/Ecorp/EntitySearch/NameSearch.aspx).
The goal is to search for many company names based on a larger list in Excel to get their founding dates. For now I am starting out with a single name to get it running. I am having trouble in my main code as there is no inherent input value in the HTML code:
<input name="ctl00$ContentPlaceHolder1$frmEntityName" type="text" id="ctl00_ContentPlaceHolder1_frmEntityName" tabindex="4" size="30" maxlength="120" class="txtNormal" onkeyup="KeyEvent1(this.id)">
I tried the following:
Sub click_search()
Dim i As SHDocVw.InternetExplorer
Set i = New InternetExplorer
i.Visible = True
i.Navigate "https://icis.corp.delaware.gov/Ecorp/EntitySearch/NameSearch.aspx"
Do While i.ReadyState <> READYSTATE_COMPLETE
Loop
Dim idoc As MSHTML.HTMLDocument
Set idock = i.Document
idoc.getElementsByTagName("input").Item("ctl00$ContentPlaceHolder1$frmEntityName").Value = "10X Genomics Inc"
End Sub
The problem I believe is the HTML code does not have inherent value = "" to begin with but it only comes up in the HTML code after you write it in.
How do I fix this and furthermore then click the search button?
The error is
"Object variable or With block variable not set"
Always use Option Explicit at the top of every VBA code file.
If the webpage in question contains ids for the elements you are interested in, use getElementById() to access them. This code works, however it does not find any records.
Option Explicit
Sub click_search()
Dim i As SHDocVw.InternetExplorer
Dim idoc As MSHTML.HTMLDocument
Set i = New InternetExplorer
i.Visible = True
i.Navigate "https://icis.corp.delaware.gov/Ecorp/EntitySearch/NameSearch.aspx"
Do While i.ReadyState <> READYSTATE_COMPLETE
Loop
Set idoc = i.Document
idoc.getElementById("ctl00_ContentPlaceHolder1_frmEntityName").Value = "10X Genomics Inc"
idoc.getElementById("ctl00_ContentPlaceHolder1_frmFileNumber").Value = "1"
idoc.getElementById("ctl00_ContentPlaceHolder1_btnSubmit").Click
End Sub

VBA error when triggering "change" event on IE input field

I'm trying to use VBA to access an internal web page using Internet Explorer, open a search window, enter search parameters and run the search. My code will click all of the buttons, find all of the text boxes and enter the parameters. But, it does not recognize any of the parameters entered using ".value" (i.e., objElement.value = "1234567"). I have written the code based on what I have read in this forum and a number of others but, obviously, I'm still missing something. When it tries to trigger the "change" event, I receive either an Error 438 - Object Doesn't Support this Property or Method, or an Error 5 - Invalid Procedure Call or Argument. The error depends on whether I use dispatchEvent or FireEvent and whether I use the collection or the element within the collection as the object. My guess is the problem lies with my declarations but, I tried a few different ones, and still get the errors.
Unfortunately, this is accessing an internal site so you won't be able to run the code. I'm hoping someone can just take a look and point me in the right direction.
Dim EPA As String
Dim EPANumb As Integer
Dim EPAList() As String
Dim PrjCnt As Long
Dim PrjList As String
Dim WS As Worksheet
Dim IE As InternetExplorerMedium
Dim URL As String
Dim HWNDSrc As Long
Dim objCollection As Object
Dim objElement As Object
Dim objEvent As Object
Dim oHtml As HTMLDocument
Dim HTMLtags As IHTMLElementCollection
'Pull list of project numbers and enter into array
fn = ThisWorkbook.Name
EPANumb = WorksheetFunction.CountA(Worksheets("Instructions").Range("B:B"))
EPANumb = EPANumb - 2
ReDim EPAList(EPANumb)
For PrjCnt = 0 To EPANumb
If EPANumb > 0 Then
EPAList(PrjCnt) = "'" & Worksheets("Instructions").Cells((PrjCnt + 2), 2).Value & "'"
Else
EPAList(PrjCnt) = Worksheets("Instructions").Cells((PrjCnt + 2), 2).Value
End If
Next
PrjList = Join(EPAList, ",")
'Open IE and navigate to URL
Set IE = New InternetExplorerMedium
IE.Visible = True 'only if you want to see what is happening
URL = "http://anysite/SnakeEyes/grid.html"
IE.navigate URL
'need If statement in case user needs to do sign on.
' Statusbar let's user know website is loading
Application.StatusBar = URL & " is loading. Please wait..."
'IE ReadyState = 4 signifies the webpage has loaded (the first loop is set to avoid inadvertently skipping over the second loop)
Do While IE.Busy = True Or IE.ReadyState <> 4: DoEvents: Loop
Application.Wait (Now + TimeValue("0:00:05"))
'Webpage Loaded
Application.StatusBar = URL & " loaded"
Set oHtml = IE.document
'HWNDScr = IE.HWND
'SetForegroundWindow HWNDScr
'Open search box and reset search parameters
oHtml.getElementById("search_grid_c_top").Click
'IE.Document.getElementById("fbox_grid_c_reset").Click
Set objEvent = oHtml.createEvent("HTMLEvents")
objEvent.initEvent "change", True, False ' **** NEW ****
Set HTMLtags = oHtml.getElementsByTagName("select")
For i = 0 To HTMLtags.Length - 1
If HTMLtags(i).className = "selectopts" Then
If EPANumb > 0 Then
HTMLtags(i).Value = "in"
Else
HTMLtags(i).Value = "eq"
End If
' HTMLtags.dispatchEvent objEvent ' **** NEW ****
Exit For
End If
Next i
Set objEvent = oHtml.createEvent("HTMLEvents")
objEvent.initEvent "change", True, False ' **** NEW ****
Set HTMLtags = oHtml.getElementsByTagName("input")
For i = 1 To HTMLtags.Length - 1
If HTMLtags(i).ID > "jqg" And HTMLtags(i).ID < "jqh" Then
HTMLtags(i).Focus
HTMLtags(i).Value = PrjList
Exit For
End If
Next i
HTMLtags(i).dispatchEvent objEvent ' **** NEW ****
'HTMLtags(i).FireEvent objEvent ' **** NEW **** DispatchEvent gives an error 438.
'FireEvent gives an error 5 if using the (i); error 438 without it.
HTML Code
Will the "change" event trigger the update for both without VBA in IE? If the "change" event is only associated with the input box and will not trigger update for dropdown list without VBA, then I think it won't work with VBA either. Besides, what the "change" event is like?
I make a demo like below and it seems that the "change" event can be triggered well, you could try to check it.
HTML code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<table>
<tbody>
<tr>
<td class="operators">
<select class="selectopts">
<option value="eq">equal</option>
<option value="in">is in</option>
<option value="ni">is not in</option>
</select>
</td>
<td class="data">
<input class="input-elm" id="jqg1" role="textbox" type="text" size="10" value="'1006191'"/>
</td>
</tr>
</tbody>
</table>
<script>
var select = document.getElementsByClassName('selectopts')(0);
var input = document.getElementById('jqg1');
input.addEventListener('change', updateValue);
function updateValue() {
select.value = "in";
}
</script>
</body>
</html>
VBA code:
Sub LOADIE()
Set ieA = CreateObject("InternetExplorer.Application")
ieA.Visible = True
ieA.navigate "http://somewebsite"
Do Until ieA.readyState = 4
DoEvents
Loop
Set doc = ieA.Document
Set Search = doc.getElementByID("jqg1")
Search.Value = "VBA"
Dim event_onChange As Object
Set event_onChange = ieA.Document.createEvent("HTMLEvents")
event_onChange.initEvent "change", True, False
Search.dispatchEvent event_onChange
'ieA.Quit
'Set ieA = Nothing
End Sub

VBA logging in to website with 2 step login

as title says i am having an error at htdoc.all.verificationcode.Value = otp
it says Run-time error '438':
Object doesn't support this property or method
i have spent an afternoon trying to find what is wrong with it and i really hope that you guys could help me out.
Dim HTMLDoc As HTMLDocument
Dim htdoc As HTMLDocument
Dim MyBrowser As InternetExplorer
Sub login()
Dim username As Range
Dim password As Range
Dim otp As Range
Dim myValue As Variant
Dim MyHTML_Element As IHTMLElement
Dim MyURL As String
MyURL = "XXXXXXXXXXXXXXXXXXXXXX"
Set MyBrowser = New InternetExplorer
MyBrowser.silent = True
MyBrowser.navigate MyURL
MyBrowser.Visible = True
Set username = Range("B1")
Set password = Range("B2")
Set otp = Range("B3")
Do
Loop Until MyBrowser.readyState = READYSTATE_COMPLETE
Set HTMLDoc = MyBrowser.document
HTMLDoc.all.UserId.Value = username
HTMLDoc.all.password.Value = password
For Each MyHTML_Element In HTMLDoc.getElementsByTagName("input")
If MyHTML_Element.Type = "submit" Then MyHTML_Element.Click: Exit For
Next
MyURL2 = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
MyBrowser.silent = True
MyBrowser.navigate MyURL2
MyBrowser.Visible = True
myValue = InputBox("Enter OTP")
Range("B3").Value = myValue
Application.Wait (Now + TimeValue("0:00:10"))
Do
Loop Until MyBrowser.readyState = READYSTATE_COMPLETE
Set htdoc = MyBrowser.document
htdoc.all.verificationcode.Value = otp
For Each MyHTML_Element In htdoc.getElementsByTagName("input")
If MyHTML_Element.Type = "btnobj" Then MyHTML_Element.Click: Exit For
Next
Err_Clear:
If Err <> 0 Then
Err.Clear
Resume Next
End If
End Sub
HTML in the webpage for the form is
<input name="verficationcode" id="verficationcode" type="password" size="18" maxlength="16" autocomplete="off">
<input name="btnobj" class="inputbutton" id="submitButton" onclick="checkSubmit(this);" type="button" value="Submit">
OK. That looks like a good start. You are going to a page, inputting some values and clicking Submit>. You have not set MyBrowser.visible to False so I'm assuming that you can see this going on.
The first thing you need is to wait while MyBrowser loads the page after you .click submit>. You will need to wait every time you go to a new page; My favorite is to put all of the waiting into a single line like this.
MyHTML_Element.Click
Do While (MyBrowser.Busy Or MyBrowser.readyState <> READYSTATE_COMPLETE): DoEvents: Loop
When you have that new page, you need to locate your OTP and store it in a variable. Look at the HTML behind the new page. You might see something like this:
<div id='One_Time_Password'>
47665489_29751678
</div>
You can put this into a variable you have previously declared like this.
dim myOTP as string
myOTP = MyBrowser.getElementsById("One_Time_Password").innerText
Now you have the password stored and you can do something with it.

Automate Internet Explorer: enter a value that has no "ID"

I'm trying to use excel VBA to automate the data entering on a intranet Webpage of my company. I know how to interact with values of a web page the fields have "id" like in the html code below
<input name="txtUserName" tabindex="1" id="txtUserName" type="text">
With that kind of html code I would use something like
IE.Document.getElementbyId("txtUserName").Value = "UserName"
The problem I'm facing is that the code associated with the field I'm trying to interact is
<HTML><HEAD><META content="IE=5.0000" http-equiv="X-UA-Compatible">
<SCRIPT type=text/javascript>
function ajusterFrames() {
var iLargeurGauche = 217;
var iLargeurDroite = 850;
var iLargeurFenetre = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
var iMarge = 0;
var sCols = "";
if (iLargeurFenetre > (iLargeurGauche + iLargeurDroite)) {
iMarge = (iLargeurFenetre - (iLargeurGauche + iLargeurDroite)) / 2;}
sCols = (iLargeurGauche + iMarge) + ",*";
document.getElementById("framesetbas").cols = sCols;
document.getElementById("cadres").style.display = "block";}
window.onload = ajusterFrames;
window.onresize = ajusterFrames;
</SCRIPT>
<TBODY>
<TR> </TR>
<TR>
<TD>
<!--RECHERCHE-->
DIV id=Projet>
<!--RECHERCHE-->
<CENTER>
<FIELDSET style="WIDTH: 600px" name="recherche">
<LEGEND style="FONT-SIZE: 10px; FONT-FAMILY: verdana; COLOR: #767676" name="legende_recherche">
<INPUT onclick=afficherRecherche(this.value); type=radio value=simple name=TypeRecherche>
</DIV><!------RECHERCHE AVANCÉE------------------------------------->
<DIV id=divAvancee>
<CENTER>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TR>
<TR>
<TR>
<TR>
<TR>
<TD align=right>
<FONT color=#003366 size=1 face=verdana>No Projet :</FONT></TD>
So I'm trying to modify the value of the field identify by: "txtNoProjet" Here's the code I could come up with, I tried many versions around this and still can't get it right.
UPDATED CODE TO INCLUDE SOLUTION
Private Sub entree_budget()
Dim i As Long
Dim IE As Object
Dim Doc As Object
Dim objElement As Object
Dim objCollection As Object
Dim buttonCollection As Object
Dim valeur_heure As Object
num_proj = Cells(1, 3) 'this is the value that I need to input
' Create InternetExplorer Object
Set IE = CreateObject("InternetExplorer.Application")
' You can uncoment Next line To see form results
IE.Visible = True
' Send the form data To URL As POST binary request
IE.Navigate "http://intranet.cima.ca/fr/application/paq/projets/index.asp?v1_lang=1"
' Wait while IE loading...
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
'UPDATED CODE BELOW
Set links = IE.Document.frames(2).Document.getElementsByTagName("input")
n = links.Length
While i < n
If links(i).Name = "txtMotCle" Then
links(i).Value = num_proj
End If
i = i+ 1
Wend
End Sub
Can anyone help me with this?
And also if I may I will the need to click the button "search" on the bottom of the form , but I can't recognize it's syntax so I don't know how to interact with it. Could someone tell me how to click the button that has this html code?
<A href="javascript:submitForm('avancee');">
<IMG border=0 alt="Rechercher un projet" src="../../../images/fr/rechercher.gif"></A>
UPDATED CODE SOLUTION FOR THIS IS:
Set links = IE.Document.frames(2).Document.getElementsByTagName("a")
n = links.LengtH
i = 0
While i < n
If links(i).href = "javascript:submitForm('avancee');" Then
Set objElement = links(i)
objElement.ClicK
End If
i = i + 1
Wend
Thank you so much in advance for the time you'll spend answering my questions.
Edited: the input elements were contained in a frame, which is why #jeeped's answer wasn't working. getElementsByTagName("input") should have returned them. Hopefully this edit will save you from having to read through the comments to find that out. To return inputs contained in a frame, use
IE.document.frames(x).document.getElementsByTagName("input")
where x is the index of the frame.
Original response below.
=======================================================
If it's zero-based, shouldn't you remove the -1 that's preventing the loop from running? That is, if there is one element, then the for loop would be iNPT = 0 to 0 and execute once. If there were two, then the .length would return 1 and =0 to 1 would execute twice, as expected.
I personally would probably include both Microsoft Internet Controls and Microsoft HTML Object Library in the references for the project so that I could use early binding and declare the variables, and then use a for each to iterate:
Dim inputs As MSHTML.IHTMLElementCollection
Dim inpt As MSHTML.IHTMLInputElement
Dim IE As New SHDocVw.InternetExplorer
IE.Visible = True
IE.navigate "http://intranet.cima.ca/fr/application/paq/projets/index.asp?v1_lang=1"
While IE.readyState <> READYSTATE_COMPLETE: DoEvents: Wend
Set inputs = IE.document.getElementsByTagName("input")
For Each inpt In inputs
If inpt.Name = "txtNoProjet" Then inpt.Value = num_proj
Next
Be aware that the HTML Object Library includes several different IHTMLElementCollections, with different numbers. In some situations you might need to use one of those instead. Also, you may need to use getAttribute to access the attribute:
If inpt.getAttribute("name") = "txtNoProjet" then inpt.Value = num_proj
The index to a collection of elements is zero-based. Assuming that there is only a single txtNoProjet you would use,
IE.Document.getElementsbyName("txtNoProjet")(0).Value = num_proj
I've had trouble with .getElementsbyName in the past. If the above does not work for you, collect all of the <input> elements and cycle through them until you find the one you want.
dim iNPT as long
for iNPT=0 to (IE.Document.getElementsbyTagName("input").length - 1)
if IE.Document.getElementsbyTagName("input")(iNPT).name = "txtNoProjet" then
IE.Document.getElementsbyTagName("input")(iNPT).value = num_proj
exit for
end if
next iNPT
One of those should get you going. The biggest problem you will run into would be duplicate names.
EDIT: addendum for clicking an image anchor
dim iIMG as long
for iIMG=0 to (IE.Document.getElementsbyTagName("img").length - 1)
if CBool(InStr(1, IE.Document.getElementsbyTagName("img")(iIMG).src, "rechercher.gif", vbTextCompare)) then
IE.Document.getElementsbyTagName("img")(iIMG).click
do while IE.Busy Or IE.ReadyState <> READYSTATE_COMPLETE: Do Events: Loop
exit for
end if
next iIMG
I usually prefer something closer to IE.Document.getElementsbyTagName("form")(0).submit but you haven't provided enough HTML source code to write that properly. You will have to adjust that code to look into your .Frames element.

Fill in website search bar using Excel VBA

I'm trying to make an Excel macro that inserts data into a web search form and then copies the results into a table. The web search form is not actually a "form", but a blank table so I can't just change the input value of the form because there is none:
<td valign="top">
<table border="0" cellspacing="0" cellpadding="2">
<tr>
<th class="navLabelText" align="left">Order:</th>
<td>
<input class="navEditField" id="opt_ordernumber_int" name="ordernumber" type="text" size="6" maxlength="6" />
</td>
</tr>
</table>
</td>
<td width="10"> </td>
The HTML just continues with more of the same types of forms (I'm guessing coded in Java since the site is a .jsp). Is there any way that I can pass values into the blank table?
Here's what I have so far:
Sub featurecode()
Dim ie As Object
Dim doc As HTMLDocument
Dim links As IHTMLElementCollection
Dim link As HTMLAnchorElement
Dim i As Integer
Dim found As Boolean
Dim todaysURL As String
Dim objElement As Object
Dim objCollection As Object
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True 'false
ie.navigate "https://website.com"
Application.StatusBar = "Loading Feature Codes"
Do Until ie.readyState = IE_READYSTATE.complete: DoEvents: Loop
Set doc = ie.document
' Find the input tag of the order form and submit button:
Set objCollection = ie.document.getElementsByTagName("input")
i = 0
While i < objCollection.Length
If objCollection(i).Name = "ordernumber" Then
' Set text for search
objCollection(i).Value = "655032"
Else
If objCollection(i).Type = "submit" And objCollection(i).Name = "Submit" Then
' "Search" button is found
Set objElement = objCollection(i)
objElement.Click
End If
End If
i = i + 1
Wend
End Sub
The part that I'm having trouble with is this:
If objCollection(i).Name = "ordernumber" Then
' Set text for search
objCollection(i).Value = "655032"
Usually you can change the HTML value of the form, but in this case there is no HTML value in the input tag, so I'm at a loss. My goal here is to simply insert an order number into the form and hit the submit button. Unfortunately I can't show you the website as it's an internal corporate site, but here's a screenshot of the relevant info: screenshot
Thanks!
I've found with some elements in VBA, including INPUT, you have to focus on the element first:
objCollection(i).Focus
objCollection(i).Value = "655032"