Fill in website search bar using Excel VBA - html

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"

Related

Interaction With WebPage VBA

I'm creating a code that allows me to open a specific site and enter value in element with the name searchByTagName=searchByTRSMP and then Type search to load the new window
But the problem that button search doesn't have a TagName or IdName only this
<td width="13%" align="center" rowSpan="1" colSpan="1">
<input name="" onclick="Javascript:document.forms[0].submit();return false;" type="image" srx="/cmh/cmh/xxxxxx" border="0"></input>
Anyone Can Light me on pressing that button with only those conditions
this Mycode :
Sub ToComb()
Dim ie As Object
Dim itm As IHTMLElement
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.navigate "http://XXXX-
XXXX.eu.airbus.XXXXXp:XXXXX/cmh/consultation/preSearchTRSTDMAS.do?
clearBackList=true&CMH_NO_STORING_fromMenu=true"
While ie.Busy Or ie.readyState <> 4: DoEvents: Wend
Set itm = ie.document.getElementsByName("searchByTRSMP")(0)
If Not itm Is Nothing Then itm.Value = "k20734"
Set Doc = ie.document
Set tags = ie.document.getElementsByTagName("")
For Each tagx In tags
If tagx.Value = "Next" Then
tagx.Click
Exit For
End If
Next
End Sub
GetElementsByTagname mean search for an element by the type of an HTML element (such as, div, p or in your example - input).
You can get all your inputs tags (elements), iterate them and identify the required input, based on it's (for example) srx attribute:
Set tags = ie.Document.GetElementsByTagname("Input")
For Each tagx In tags
If tagx.src= "/cmh/cmh/xxxxxx" Then
tagx.Click
End If
Next
In addition, the final src of the input might changed from the actual code, because you use a relative path. Check the actual src with a MsgBox:
For Each tagx In tags
MsgBox tagx.src
I assume it will be different, such as prefix of http and so on:
If tagx.src = "http://xxxx
xxxx.eu.airbus.xxx:xxxx/cxxx/xxx/image/button_search.gif" Then

Getting VBA to Reference and Accept 2 Word Source Code (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.

Take data from next HTML tag

Using this HTML code for example:
<table class="table-grid">
<tr>
<th>auto.model</th>
<td>
<pre>'Toyota Avensis Wagon'</pre>
</td>
</tr>
<tr>
<th>auto.year</th>
<td>
<pre>2005</pre>
</td>
</tr>
</table>
If I take the parameter "auto.model" between <th></th> tags and want to receive "Toyota Avensis Wagon", i.e. the next expression between <pre></pre>. Ideally I'd like to have function to do it.
Thank you #Jeeped, but code raise "Type mismatch" error and points to Set el = Param.PreviousSibling:
Sub Extract_TD_text()
Dim URL As String
Dim IE As InternetExplorer
Dim HTMLdoc As HTMLDocument
Dim Params As IHTMLElementCollection
Dim Param As HTMLTableCell
Dim Val As HTMLTableCell
Dim r As Long
Dim el As HTMLTableCell
URL = "My URL"
Set IE = New InternetExplorer
With IE
.navigate URL
.Visible = False
'Wait for page to load
While .Busy Or .READYSTATE <> READYSTATE_COMPLETE: DoEvents: Wend
Set HTMLdoc = .document
End With
Set Params = HTMLdoc.getElementsByTagName("tr")
For Each Param In Params
If Param.innerText Like "*auto.model*" Then
Set el = Param.PreviousSibling
Exit For
End If
Next
If Not el Is Nothing Then Debug.Print el.innerText
IE.Quit
Set IE = Nothing
End Sub
Instead of using previousSibling, I'd like to suggest nextElementSibling.
From the way your HTML and VBA codes are currently set up, the current 'param' value being passed should be the <th> tag. I think previousSibling would likely check the tag that comes before that, and since is the first element within the <tr> (the parent element), there shouldn't be anything (except maybe an invisible node- which previousSibling can find, but that we don't need).
I think nextElementSibling should be able to find your <td> tag, since it comes after your <th> tag.

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.

Use Excel VBA to click on a button in Internet Explorer, when the button has no "name" associated

I'm trying to use excel to automate the value entering in a time sheet. The time sheet is on a web page.
Right now I'm able to load the page, enter my username and password and then entering the time sheet by itself. See code below.
At this point I need to click on a button to open sub-forms. I can't know in advance how many sub-forms there will be to open. I know how to click on a button when it has a "name". But in this case there's none. So my updated code below use a loop to open every other subform. It works the first time, but when I do it again
Could someone point me how to determine how many of those button there is in the page and how to click on each?
Following I'm placing the code I have until now and below it, the HTML code of the page I need to interact with.
Private Sub time_sheet_filling()
Dim I As Long
Dim IE As Object
Dim doc As Object
Dim objElement As Object
Dim objCollection As Object
' Create InternetExplorer Object
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
' Send the form data To URL As POST binary request
IE.navigate "http://timesheet.cccc.ca/timesheet/"
' Wait while IE loading...
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
'Load the logon page
Set objCollection = IE.Document.getElementsByTagName("input")
I = 0
While I < objCollection.Length
If objCollection(I).Name = "txtUserName" Then
' Set text to enter
objCollection(I).Value = "6666"
End If
If objCollection(I).Name = "txtPwd" Then
' Set text for password
objCollection(I).Value = "password"
End If
If objCollection(I).Type = "submit" And objCollection(I).Name = "btnSubmit" Then ' submit button clicking
Set objElement = objCollection(I)
End If
I = I + 1
Wend
objElement.Click ' click button to load the form
' Wait while IE re-loading...
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
' Show IE
IE.Visible = True
Dim links, link
Dim n, j
Set links = IE.Document.getElementById("dgTime").getElementsByTagName("a")
n = links.Length
For j = 0 To n - 1 Step 2
links(j).Click
'I have some operations to be done will post another question for this
IE.Document.getElementById"DetailToolbar1_lnkBtnSave").Click 'save
IE.Document.getElementById"DetailToolbar1_lnkBtnCancel").Click 'close
Next
End Sub
So extract of the html code is below. I'm trying to click the button that is coded in the last line of the html code below
<table width="984" class="Grid" id="dgTime" border="1" rules="all" cellspacing="0">
<tbody>
<tr class="GridHeader">
</tr>
<tr class="GridItem">
</tr>
<tr class="GridItem">
<td class="GridButtonColumn">
<a href="javascript:__doPostBack('dgTime$_ctl2$_ctl0','')">
<img src="images/toolbar/b_edit.gif">
</a>
</td
Tx Tim for the answers. Now I'm able to select the first subform button to open it.
links(j).click 'j = 0
I then save it, close, and come back to the main form. But then when I try to do
links(j).click 'j = 2 this time
the second time I get a runtime error 70: permission denied. Anymore kind help will be so appreciated.
Regards
With the kind help from Tim Williams, I finally figured out the last détails that were missing. Here's the final code below.
Private Sub Open_multiple_sub_pages_from_main_page()
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
' 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://webpage.com/"
' Wait while IE loading...
While IE.Busy
DoEvents
Wend
Set objCollection = IE.Document.getElementsByTagName("input")
i = 0
While i < objCollection.Length
If objCollection(i).Name = "txtUserName" Then
' Set text for search
objCollection(i).Value = "1234"
End If
If objCollection(i).Name = "txtPwd" Then
' Set text for search
objCollection(i).Value = "password"
End If
If objCollection(i).Type = "submit" And objCollection(i).Name = "btnSubmit" Then ' submit button if found and set
Set objElement = objCollection(i)
End If
i = i + 1
Wend
objElement.Click ' click button to load page
' Wait while IE re-loading...
While IE.Busy
DoEvents
Wend
' Show IE
IE.Visible = True
Set Doc = IE.Document
Dim links, link
Dim j As Integer 'variable to count items
j = 0
Set links = IE.Document.getElementById("dgTime").getElementsByTagName("a")
n = links.Length
While j <= n 'loop to go thru all "a" item so it loads next page
links(j).Click
While IE.Busy
DoEvents
Wend
'-------------Do stuff here: copy field value and paste in excel sheet. Will post another question for this------------------------
IE.Document.getElementById("DetailToolbar1_lnkBtnSave").Click 'save
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now) 'wait
Loop
IE.Document.getElementById("DetailToolbar1_lnkBtnCancel").Click 'close
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now) 'wait
Loop
Set links = IE.Document.getElementById("dgTime").getElementsByTagName("a")
j = j + 2
Wend
End Sub
IE.Document.getElementById("dgTime").getElementsByTagName("a")(0).Click
EDIT: to loop through the collection (items should appear in the same order as they are in the source document)
Dim links, link
Set links = IE.Document.getElementById("dgTime").getElementsByTagName("a")
'For Each loop
For Each link in links
link.Click
Next link
'For Next loop
Dim n, i
n = links.length
For i = 0 to n-1 Step 2
links(i).click
Next I
CSS selector:
Use a CSS selector of img[src='images/toolbar/b_edit.gif']
This says select element(s) with img tag with attribute src having value of 'images/toolbar/b_edit.gif'
CSS query:
VBA:
You can apply the selector with the .querySelector method of document.
IE.document.querySelector("img[src='images/toolbar/b_edit.gif']").Click