In the below code I'm trying to click on the "About" link (href) in the www.google.co.in website. This worked on IE11 (Windows 10), but is not working for IE10 (Windows 7). Is this in anyway machine dependent. If not what is the right code?
Please remember I'm trying to click on a link in an already opened browser window.
Set objShell = CreateObject("Shell.Application")
IE_count = objShell.Windows.Count
For x = 0 To (IE_count - 1)
On Error Resume Next ' sometimes more web pages are counted than are open
my_url = objShell.Windows(x).Document.Location
my_title = objShell.Windows(x).Document.Title
'You can use my_title of my_url, whichever you want
If my_title Like "Google" & "*" Then 'identify the existing web page
Set ie = objShell.Windows(x)
Exit For
Else
End If
Next
Dim LinkHref
Dim a
LinkHref = "//www.google.co.in/intl/en/about.html?fg=1"
For Each a In ie.Document.GetElementsByTagName("A")
If LCase(a.GetAttribute("href")) = LCase(LinkHref) Then
a.Click
Exit For ''# to stop after the first hit
End If
Next
You can achieve the goal with descriptive programming in QTP (if you don't want to use the object repository for some reason). This code should give you an example of what you can do:
Dim oDesc ' create a Description object for objects of class Link
Set oDesc = Description.Create
oDesc("micclass").value = "Link"
'Find all the Links in the browser using ChildObjects
Set obj = Browser("title=Google").Page("title=Google").ChildObjects(oDesc)
Dim i
'obj.Count value has the number of links in the page
For i = 0 to obj.Count - 1 ' indexed from zero, so use 0 to Count -1
'get the name of all the links in the page
If obj(i).GetROProperty("innerhtml")= LinkHref Then
obj(i).Click 'click the link if it matched the href you specfied
Exit For ' no need to carry on the loop if we found the right link
End If
Next
If you just need to use vbscript, you can do it like this:
Dim oShell : Set oShell = CreateObject("Shell.Application")
Dim oWindow
For Each oWindow In oShell.Windows
If InStr(oWindow.FullName, "iexplore") > 0 Then
If InStr(1, oWindow.Document.Title, "Google", vbTextCompare) > 0 Then
Set ieApp = oWindow
Exit For
End If
End If
Next
LinkHref = "//www.google.co.in/intl/en/about.html?fg=1"
For Each linky In ieApp.Document.GetElementsbyTagName("a")
If LCase(linky.GetAttribute("href")) = LCase(LinkHref) Then
linky.Click
Exit For
End If
Next
This is pretty much the answer given above by Ansgar, but with a little extra to fix the object error. Only a browser window has the Document.Title, and the loop is working through every window that's open, so you get the error when the loop tries a non IE window. This version fixes that by only checking for the Document.Title if the window has been identified as an IE instance in the first place.
Don't know about QTP, but VBScript doesn't have a Like operator.
This is the usual way to attach to an IE window with a specific title in plain VBScript:
Set app = CreateObject("Shell.Application")
For Each wnd In app.Windows
If wnd.Name = "Internet Explorer" Then
If InStr(1, wnd.Document.Title, "Google", vbTextCompare) > 0 Then
Set ie = wnd
Exit For
End If
End If
Next
Related
Greetings to everyone.
GOAL
I want to open flashscore.com and get data related to soccer matches.
I want all the matches of this season, so the link "Show more matches" will have to be clicked one or more times.
RESTRICTIONS
I need to do this using VBA
This site does not support Internet Explorer
I cannot install anything on the pc that will be used, so Selenium is turned down as an option
Bearing in mind all of the above, the only option left, seems to be the Microsoft XML, v6.0 library.
WHAT I 'VE TRIED
I 've read several possible duplicates to this post and tried their solutions, but nothing seemed to help so far.
Here is the code with comments explaining every situation:
Option Explicit
Sub Get_Matches()
'REFERENCE TO Microsoft XML, v6.0
Dim httpReq As New MSXML2.XMLHTTP60
Dim doc As MSHTML.HTMLDocument
Dim eleCol As Object
Dim ele As MSHTML.HTMLHtmlElement
'Open site and get html. In comments:things proposed by others but seemed to make no change.
httpReq.Open "GET", "https://www.flashscore.com/football/england/premier-league-2019-2020/results/"
'httpReq.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
httpReq.send
Set doc = New MSHTML.HTMLDocument
doc.body.innerHTML = httpReq.responseText
'doc.body.innerHTML = httpReq.responseBody
'Tried to get the div containing the first match:
Set ele = doc.getElementById("g_1_2JDks1o7") '--> returns nothing
'Tried to get the "Show more matches" link:
Set ele = doc.getElementsByClassName("event__more")(0) '--> returns nothing
'Tried to get the first ancestor that has an id:
Set ele = doc.getElementById("live-table") '--> returns nothing
'Tried to get all <a> elements and then narrow them down till I find the "Show more matches" link:
Set eleCol = doc.getElementsByTagName("a")
For Each ele In eleCol
If ele.href Like "*[#]*" And ele.innerText = "Show more matches" Then
Exit For
End If
Next ele
ele.Click '--> I get the "Show more matches" link, but nothing seems to change
'Someone suggested firing onclick event.
ele.FireEvent "onclick" '--> did nothing
'Some people suggested waiting.
'So I tried this:
Do
DoEvents
Loop While doc.readyState = "loading"
If doc.readyState <> "complete" Then GoTo ERROR_END
Set doc = New MSHTML.HTMLDocument
doc.body.innerHTML = httpReq.responseText
'and the Delay_Code_By function below,
Set ele = doc.getElementById("live-table") '--> but still returns nothing
'Some people suggested looping, so the document gets loaded first.
Do: Set ele = doc.getElementById("live-table"): DoEvents: Loop While ele Is Nothing '--> resulted to infinite loop.
Do: Set eleCol = doc.getElementsByClassName("event__more"): DoEvents: Loop Until eleCol.Length > 0 '--> resulted to infinite loop.
'This block extracts html in a txt file in desktop, to help me see it, as it is at runtime.
'------------------------------------------------------------------------------------------
' Dim fso As Scripting.FileSystemObject
' Dim txtFile As Scripting.TextStream
' Set fso = New Scripting.FileSystemObject
' Set txtFile = fso.OpenTextFile(CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\output.txt", 2, True, TristateTrue)
' txtFile.Write httpReq.responseText
' txtFile.Close
' Set txtFile = Nothing
' Set fso = Nothing
'------------------------------------------------------------------------------------------
'Inside the txt file I found html code that onclick calls some kind of function:
'Tried to call this function:
doc.parentWindow.execScript "document.body.classList.toggle('loading', true);", "JScript" '--> throws automation error (probably there's some error with my syntax).
'I also tried to call this function:
doc.parentWindow.execScript "function(){return cjs.Api.loader.get('cjs').call(function(_cjs){loadMoreGames(_cjs);});};" '--> which did not throw error but did nothing.
Exit Sub
ERROR_END:
MsgBox "error"
End Sub
Public Sub Delay_Code_By(seconds As Integer)
Dim endTime As Date
endTime = DateAdd("s", seconds, Now)
Do While Now < endTime
DoEvents
Loop
End Sub
QUESTIONS
If there is any other option that I'm missing, other than using Microsoft XML, v6.0 library, please tell me to try it.
As far as I understand the problem is that the elements I'm trying to get are not present the moment I try to get them. If I am correct, can anyone please explain me why is this happening and a possible workaround this one? If I am wrong please point me to the right direction.Thank you.
UPDATE
I'm posting this screenshot based on #QHarr 's comment about watching the network/xhr tab.
I am trying to automate IE through VBA to click a button that is embedded in an "iframe" as on screenshot below (image in the last line):
However my code is unsuccesful in referencing the button (the last line doesn't print any value):
Sub intercept()
Dim my_title As String
my_title = "Accounting"
marker = 0
Set objShell = CreateObject("Shell.Application")
IE_count = objShell.Windows.Count
For x = 0 To (IE_count - 1)
On Error Resume Next ' sometimes more web pages are counted than are open
page_url = objShell.Windows(x).Document.Location
page_title = objShell.Windows(x).Document.Title
If page_title Like my_title & "*" Then 'compare to find if the desired web page is already open
Set IE = objShell.Windows(x)
marker = 1
Exit For
Else
End If
Next
If marker = 0 Then
MsgBox ("A matching webpage was NOT found")
Else
MsgBox ("A matching webpage was found")
End If
Set mytable = IE.Document.frames(1).Document.tables(1)
Debug.Print mytable.getElementsByTagName("td").Length
End Sub
I have also tried: IE.Document.frames(0).Document.tables(0).
Any help on how to click on this element is appreciated.
I am in need of editing html code using VBA. I actually got this working as far as editing values of text boxes. My problem is that when I simulate clicking the "submit" button there are new tables that come up. The web address stays the same but now there is new html code generated for the tables. I am trying to read data from these tables but it seems as if they don't exist when I try and query them. So I am guessing that I need to update or refresh the IE html code after I press the "submit" button. I can not seem to figure out how to do this. Any help is greatly appreciated. Here is my code so far:
Sub ImportStackOverflowData()
Dim SearchFor As IHTMLElement
Dim RowNumber As Long
RowNumber = 4
'to refer to the running copy of Internet Explorer
Dim ie As InternetExplorer
'to refer to the HTML document returned
Dim html As HTMLDocument
'open Internet Explorer in memory, and go to website
Set ie = New InternetExplorer
ie.Visible = True
ie.Navigate "http://google.com"
'Wait until IE is done loading page
Do While ie.ReadyState <> READYSTATE_COMPLETE
Application.StatusBar = "Trying to go to TRSDataBase ..."
DoEvents
Loop
Set html = ie.Document
Application.StatusBar = ""
'clear old data out and put titles in
Cells.Clear
Set SearchFor = html.getElementById("ddl_process")
'if this is the tag containing the question details, process it
If SearchFor.ID = "ddl_process" Then
'Replace the value of dl-process with copperhead name
Call SearchFor.setAttribute("value", "CPHB_FAT")
Cells(RowNumber, 1).Value = "Successfully replaced ddl_process to : " &
SearchFor.getAttribute("value")
'go on to next row of worksheet
RowNumber = RowNumber + 1
End If
Set SearchFor = html.getElementById("txt_startdate")
If SearchFor.ID = "txt_startdate" Then
'Replace the value of dl-process with copperhead name
Call SearchFor.setAttribute("value", "07-07-17")
Cells(RowNumber, 1).Value = "Successfully replaced startdate to : " &
SearchFor.getAttribute("value")
'go on to next row of worksheet
RowNumber = RowNumber + 1
End If
Set SearchFor = html.getElementById("txt_enddate")
If SearchFor.ID = "txt_enddate" Then
'Replace the value of dl-process with copperhead name
Call SearchFor.setAttribute("value", "07-14-17")
Cells(RowNumber, 1).Value = "Successfully replaced enddate to : " &
SearchFor.getAttribute("value")
'go on to next row of worksheet
RowNumber = RowNumber + 1
End If
'find view button and click it
Set SearchFor = html.getElementById("btn_header")
If SearchFor.ID = "btn_header" Then
SearchFor.Click
Cells(RowNumber, 1).Value = "The View Button has been clicked."
'go on to next row of worksheet
RowNumber = RowNumber + 1
End If
'Now get data from table after it loads
Application.Wait (Now + TimeValue("0:00:20"))
Set html = ie.Document <----------This is where i am trying to update or refresh my code after it loads with the new tables
Debug.Print ie.Document.body.innerHTML
Range("L5").Value = ie.Document.getElementsByTag("table")
(1).Rows(1).Cells(2).innerText
Try getting a new pointer to the window. Sometimes that does the trick.
Public Function FindWindow(SearchBy As String, SearchCriteria As String) As Object
Dim Window As Object
For Each Window In CreateObject("Shell.Application").Windows
If SearchBy = "URL" And Window.LocationURL Like "*" & SearchCriteria & "*" Then
Set FindWindow = Window
Exit Function
ElseIf SearchBy = "Name" And Window.LocationName Like "*" & SearchCriteria & "*" Then
Set FindWindow = Window
Exit Function
End If
Next
Set FindWindow = Nothing
End Function
Sub getNewPointer()
Dim ie As InternetExplorer
ie.Navigate "www.google.com"
'Wait for the page to load and do actions etc
'Your code here
'
'
'Clear the IE reference
Set ie = Nothing
'get a new pointer to the window of interest
'Keep in mind it finds the first matching Window based on your criteria!
Set ie = FindWindow("URL", "www.google.ca")
'Try getting the property you want
Debug.Print
End Sub
Aim
I am looking to scrape 20/20 cricket scorecard data from the Cricinfo website, ideally into CSV form for data analysis in Excel
As an example the current Australian Big Bash 2011/12 scorecards are available from
Game 1: http://www.espncricinfo.com/big-bash-league-2011/engine/match/524915.html
Last Game: http://www.espncricinfo.com/big-bash-league-2011/engine/match/524935.html
Background
I am proficient in using VBA (either automating IE or using XMLHTTP and then using regular expressions) to scrape data from websites, ie
Extract values from HTML TD and Tr
In that same question a comment was posted suggesting html parsing - which I hadn't come accross before - so I have taken a look at questions such as RegEx match open tags except XHTML self-contained tags
Query
While I could write a regex to parse the cricket data below I would like advice as to how I could efficiently retrieve these results with html parsing.
Please bear in mind that my preference is a repeatable CSV format containing:
the date/name of the match
Team 1 name
the output should dump up to 11 records for Team 1 (blank records where players haven't batted, ie "Did Not Bat")
Team 2 name
the output should dump up to 11 records for Team 2 (blank records where players haven't batted)
Nirvana for me would be a solution that I could deploy using VBA or VBscript so I could fully automate my analysis, but I presume I will have to use a separate tool for the html parse.
Sample Site links and Data to be Extracted
There are 2 techniques that I use for "VBA". I will describe them 1 by one.
1) Using FireFox / Firebug Addon / Fiddler
2) Using Excel's inbuilt facility to get data from the web
Since this post will be read by many so I will even cover the obvious. Please feel free to skip whatever part you know
1) Using FireFox / Firebug Addon / Fiddler
FireFox : http://en.wikipedia.org/wiki/Firefox
Free download (http://www.mozilla.org/en-US/firefox/new/)
Firebug Addon: http://en.wikipedia.org/wiki/Firebug_%28software%29
Free download (https://addons.mozilla.org/en-US/firefox/addon/firebug/)
Fiddler : http://en.wikipedia.org/wiki/Fiddler_%28software%29
Free download (http://www.fiddler2.com/fiddler2/)
Once you have installed Firefox, install the Firebug Addon. The Firebug Addon lets you inspect the different elements in a webpage. For example if you want to know the name of a button, simply right click on it and click on "Inspect Element with Firebug" and it will give you all the details that you will need for that button.
Another example would be finding the name of a table on a website which has the data that you need scrapped.
I use Fiddler only when I am using XMLHTTP. It helps me to see the exact info being passed when you click on a button. Because of the increase in the number of BOTS which scrape the sites, most sites now, to prevent automatic scrapping, capture your mouse coordinates and pass that information and fiddler actually helps you in debugging that info that is being passed. I will not get into much details here about it as this info can be used maliciously.
Now let's take a simple example on how to scrape the URL posted in your question
http://www.espncricinfo.com/big-bash-league-2011/engine/match/524915.html
First let's find the name of the table which has that info. Simply right click on the table and click on "Inspect Element with Firebug" and it will give you the below snapshot.
So now we know that our data is stored in a table called "inningsBat1" If we can extract the contents of that table to an Excel file then we can definitely work with the data to do our analysis. Here is sample code which will dump that table in Sheet1
Before we proceed, I would recommend, closing all Excel and starting a fresh instance.
Launch VBA and insert a Userform. Place a command button and a webcrowser control. Your Userform might look like this
Paste this code in the Userform code area
Option Explicit
'~~> Set Reference to Microsoft HTML Object Library
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub CommandButton1_Click()
Dim URL As String
Dim oSheet As Worksheet
Set oSheet = Sheets("Sheet1")
URL = "http://www.espncricinfo.com/big-bash-league-2011/engine/match/524915.html"
PopulateDataSheets oSheet, URL
MsgBox "Data Scrapped. Please check " & oSheet.Name
End Sub
Public Sub PopulateDataSheets(wsk As Worksheet, URL As String)
Dim tbl As HTMLTable
Dim tr As HTMLTableRow
Dim insertRow As Long, Row As Long, col As Long
On Error GoTo whoa
WebBrowser1.navigate URL
WaitForWBReady
Set tbl = WebBrowser1.Document.getElementById("inningsBat1")
With wsk
.Cells.Clear
insertRow = 0
For Row = 0 To tbl.Rows.Length - 1
Set tr = tbl.Rows(Row)
If Trim(tr.innerText) <> "" Then
If tr.Cells.Length > 2 Then
If tr.Cells(1).innerText <> "Total" Then
insertRow = insertRow + 1
For col = 0 To tr.Cells.Length - 1
.Cells(insertRow, col + 1) = tr.Cells(col).innerText
Next
End If
End If
End If
Next
End With
whoa:
Unload Me
End Sub
Private Sub Wait(ByVal nSec As Long)
nSec = nSec + Timer
While Timer < nSec
DoEvents
Sleep 100
Wend
End Sub
Private Sub WaitForWBReady()
Wait 1
While WebBrowser1.ReadyState <> 4
Wait 3
Wend
End Sub
Now run your Userform and click on the Command button. You will notice that the data is dumped in Sheet1. See snapshot
Similarly you can scrape other info as well.
2) Using Excel's inbuilt facility to get data from the web
I believe you are using Excel 2007 so I will take that as an example to scrape the above mentioned link.
Navigate to Sheet2. Now navigate to Data Tab and click on the button "From Web" on the extreme right. See snapshot.
Enter the url in the "New Web Query Window" and click on "Go"
Once the page is uploaded, select the relevant table that you want to import by clicking on the small arrow as shown in the snapshot. Once done, click on "Import"
Excel will then ask you where you want the data to be imported. Select the relevant cell and click on OK. And you are done! The data will be imported to the cell which you specified.
If you wish you can record a macro and automate this as well :)
Here is the macro that I recorded.
Sub Macro1()
With ActiveSheet.QueryTables.Add(Connection:= _
"URL;http://www.espncricinfo.com/big-bash-league-2011/engine/match/524915.html" _
, Destination:=Range("$A$1"))
.Name = "524915"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.WebSelectionType = xlSpecifiedTables
.WebFormatting = xlWebFormattingNone
.WebTables = """inningsBat1"""
.WebPreFormattedTextToColumns = True
.WebConsecutiveDelimitersAsOne = True
.WebSingleBlockTextImport = False
.WebDisableDateRecognition = False
.WebDisableRedirections = False
.Refresh BackgroundQuery:=False
End With
End Sub
Hope this helps. Let me know if you still have some queries.
Sid
For anyone else interested in this I ended up using the code below based on Siddhart Rout's earlier answer
XMLHttp was significantly quicker than automating IE
the code generates a CSV file for each series to be dowloaded (held in the X variable)
the code dumps each match to a regular 29 row range (regardless of how many players batted) to facillitate easier analysis later on
Public Sub PopulateDataSheets_XML()
Dim URL As String
Dim ws As Worksheet
Dim lngRow As Long
Dim lngRecords As Long
Dim lngWrite As Long
Dim lngSpare As Long
Dim lngInnings As Long
Dim lngRow1 As Long
Dim X(1 To 15, 1 To 4) As String
Dim objFSO As Object
Dim objTF As Object
Dim xmlHttp As Object
Dim htmldoc As HTMLDocument
Dim htmlbody As htmlbody
Dim tbl As HTMLTable
Dim tr As HTMLTableRow
Dim strInnings As String
s = Timer()
Set xmlHttp = CreateObject("MSXML2.ServerXMLHTTP")
Set objFSO = CreateObject("scripting.filesystemobject")
X(1, 1) = "http://www.espncricinfo.com/indian-premier-league-2011/engine/match/"
X(1, 2) = 501198
X(1, 3) = 501271
X(1, 4) = "indian-premier-league-2011"
X(2, 1) = "http://www.espncricinfo.com/big-bash-league-2011/engine/match/"
X(2, 2) = 524915
X(2, 3) = 524945
X(2, 4) = "big-bash-league-2011"
X(3, 1) = "http://www.espncricinfo.com/ausdomestic-2010/engine/match/"
X(3, 2) = 461028
X(3, 3) = 461047
X(3, 4) = "big-bash-league-2010"
Set htmldoc = New HTMLDocument
Set htmlbody = htmldoc.body
For lngRow = 1 To UBound(X, 1)
If Len(X(lngRow, 1)) = 0 Then Exit For
Set objTF = objFSO.createtextfile("c:\temp\" & X(lngRow, 4) & ".csv")
For lngRecords = X(lngRow, 2) To X(lngRow, 3)
URL = X(lngRow, 1) & lngRecords & ".html"
xmlHttp.Open "GET", URL
xmlHttp.send
Do While xmlHttp.Status <> 200
DoEvents
Loop
htmlbody.innerHTML = xmlHttp.responseText
objTF.writeline X(lngRow, 1) & lngRecords & ".html"
For lngInnings = 1 To 2
strInnings = "Innings " & lngInnings
objTF.writeline strInnings
Set tbl = Nothing
On Error Resume Next
Set tbl = htmlbody.Document.getElementById("inningsBat" & lngInnings)
On Error GoTo 0
If Not tbl Is Nothing Then
lngWrite = 0
For lngRow1 = 0 To tbl.Rows.Length - 1
Set tr = tbl.Rows(lngRow1)
If Trim(tr.innerText) <> vbNewLine Then
If tr.Cells.Length > 2 Then
If tr.Cells(1).innerText <> "Extras" Then
If Len(tr.Cells(1).innerText) > 0 Then
objTF.writeline strInnings & "-" & lngWrite & "," & Trim(tr.Cells(1).innerText) & "," & Trim(tr.Cells(3).innerText)
lngWrite = lngWrite + 1
End If
Else
objTF.writeline strInnings & "-" & lngWrite & "," & Trim(tr.Cells(1).innerText) & "," & Trim(tr.Cells(3).innerText)
lngWrite = lngWrite + 1
Exit For
End If
End If
End If
Next
For lngSpare = 12 To lngWrite Step -1
objTF.writeline strInnings & "-" & lngWrite + (12 - lngSpare)
Next
Else
For lngSpare = 1 To 13
objTF.writeline strInnings & "-" & lngWrite + (12 - lngSpare)
Next
End If
Next
Next
Next
'Call ConsolidateSheets
End Sub
RegEx is not a complete solution for parsing HTML because it is not guaranteed to be regular.
You should use the HtmlAgilityPack to query the HTML. This will allow you to use the CSS selectors to query the HTML similar to how you do it with jQuery.
As quite a few people may see this I thought I would use it as a chance to demonstrate a few features I rarely see people using in VBA web-scraping: deleteRow, querySelector and use of clipboard to write out a table (complete with formatting and hyperlinks) to a sheet based on the table.outerHTML.
deleteRow is used to remove the unwanted rows. querySelector is used to apply faster css selectors to match on nodes. Modern browsers/html parsers are optimized for css and class selectors (which I use) are the second fastest selector type (after id).
Use of css selectors and understanding htmlTable methods/properties will allow for much greater flexibility in your web-scraping endeavours. Understanding the use of the clipboard means a simple copy paste method for transferring a table to Excel.
Execution could easily be tied to a button push and the url read in from a cell.
VBA:
Option Explicit
Public Sub test()
WriteOutTable "https://www.espncricinfo.com/series/8044/scorecard/524935/hobart-hurricanes-vs-melbourne-stars-big-bash-league-2011-12"
End Sub
Public Sub WriteOutTable(ByVal url As String)
'required VBE (Alt+F11) > Tools > References > Microsoft HTML Object Library ; Microsoft XML, v6 (your version may vary)
Dim hTable As MSHTML.HTMLTable, clipboard As Object
Dim xhr As MSXML2.xmlhttp60, html As MSHTML.htmlDocument
Set xhr = New MSXML2.xmlhttp60
Set html = New MSHTML.htmlDocument
With xhr
.Open "GET", url, False
.Send
html.body.innerHTML = .responseText
End With
Set hTable = html.querySelector(".batsman")
rowCount = hTable.Rows.Length - 1
For i = rowCount To 0 Step -1
Select Case True
Case i = rowCount Or i = rowCount - 1 Or InStr(hTable.Rows(i).outerHTML, "wicket-details") > 0
hTable.deleteRow i
End Select
Next
Set clipboard = GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
clipboard.SetText hTable.outerHTML
clipboard.PutInClipboard
ActiveSheet.Cells(1, 1).PasteSpecial
End Sub
I have created an application form using MS Word and a whole bunch of form fields, and I have an Access db that can import all the data I need from this Word doc, thanks to this:
http://msdn.microsoft.com/en-us/library/aa155434%28office.10%29.aspx
Now everything works just fine (I even managed to get it to import into multiple tables!), but the problem with the above is that I have to manually enter the name of each file one at a time... which is fine if it's just a case of importing the application form as it comes in... but I have quite a lot sitting in a folder that needs entered into the database.
Then I found this:
How to show "Open File" Dialog in Access 2007 VBA?
I've tried to tweak and merge the two to make it work... but as you can guess, to no avail... (it doesn't help when I'm very much an Access novice!)
What I am looking to do is to be able to import a bunch of Word docs / form fields into MS Access by using the Open / Select file dialogue box... what I've got works, but I'd like to make it easier to work with!
Thanks everyone
Jake
##### Codes I been using
Option Compare Database
Option Explicit
Private Sub cmdFileDialog_Click()
' This requires a reference to the Microsoft Office 11.0 Object Library.
Dim fDialog As Office.FileDialog
Dim varFile As Variant
Dim appWord As Word.Application
Dim doc As Word.Document
' Dim cnn As New ADODB.Connection
' Dim rst As New ADODB.Recordset
Dim strDocName As String
Dim blnQuitWord As Boolean
' Clear the list box contents.
' Me.FileList.RowSource = ""
' Set up the File dialog box.
Set fDialog = Application.FileDialog(msoFileDialogFilePicker)
With fDialog
' Allow the user to make multiple selections in the dialog box.
.AllowMultiSelect = True
' Set the title of the dialog box.
.Title = "Select One or More Files"
' Clear out the current filters, and then add your own.
.Filters.Clear
.Filters.Add "Microsoft Word", "*.DOC"
.Filters.Add "All Files", "*.*"
' Show the dialog box. If the .Show method returns True, the
' user picked at least one file. If the .Show method returns
' False, the user clicked Cancel.
If .Show = True Then
' Loop through each file that is selected and then add it to the list box.
For Each varFile In .SelectedItems
' Me.FileList.AddItem varFile
Set appWord = GetObject(, "Word.Application")
Set doc = appWord.Documents.Open(varFile)
' cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
' "Data Source=M:\Medical\GPAppraisal\Contacts & Databases\" & _
' "AppForm.mdb;"
' rst.Open "tbl_Applicants", cnn, _
' adOpenKeyset, adLockOptimistic
' With rst
.addnew
!Title = doc.FormFields("wTitle").Result
!FirstName = doc.FormFields("wFirstName").Result
!LastName = doc.FormFields("wLastName").Result
!Address1 = doc.FormFields("wAddress1").Result
!Address2 = doc.FormFields("wAddress2").Result
!Address3 = doc.FormFields("wAddress3").Result
!City = doc.FormFields("wCity").Result
!PostCode = doc.FormFields("wPostCode").Result
!Email = doc.FormFields("wEmail").Result
!Phone1 = doc.FormFields("wPhone1").Result
!Phone2 = doc.FormFields("wPhone2").Result
!LM = doc.FormFields("wLM").Result
!LMAddress1 = doc.FormFields("wLMAddress1").Result
!LMAddress2 = doc.FormFields("wLMAddress2").Result
!LMAddress3 = doc.FormFields("wLMAddress3").Result
!LMCity = doc.FormFields("wLMCity").Result
!LMPostCode = doc.FormFields("wLMPostCode").Result
!LMEmail = doc.FormFields("wLMEmail").Result
!LMPhone = doc.FormFields("wLMPhone").Result
!LMOK = doc.FormFields("wLMOK").Result
!Probity = doc.FormFields("wProbity").Result
!Practising = doc.FormFields("wPractising").Result
!Signature = doc.FormFields("wSignature").Result
!AppDate = doc.FormFields("wAppDate").Result
!e2011012028 = doc.FormFields("w2011012028").Result
!e2011021725 = doc.FormFields("w2011021725").Result
!e2011030311 = doc.FormFields("w2011030311").Result
!e2011031625 = doc.FormFields("w2011031625").Result
!e20110203 = doc.FormFields("w20110203").Result
!e20110211 = doc.FormFields("w20110211").Result
!e20110322 = doc.FormFields("w20110322").Result
!e20110330 = doc.FormFields("w20110330").Result
.Update
.Close
End With
doc.Close
If blnQuitWord Then appWord.Quit
cnn.Close
MsgBox "Application Imported!"
Cleanup:
' Set rst = Nothing
' Set cnn = Nothing
Set doc = Nothing
Set appWord = Nothing
Next
Else
MsgBox "You clicked Cancel in the file dialog box."
End If
End With
End Sub
#
I've tried to mess with me.tables and me!forms and .add etc etc - obviously I'm a complete novice here!!!
What I want is to be able to import data from form fields in a Word Doc into a MS Access table (which I have managed to do with the first URL in my original post above); by means of selecting the Word doc from the Open/Select dialogue box, instead of manually entering the names of each Word doc.
My apologies if it sounds obvious or simple - Access is not my strong point by any means!
Before I begin I didn't understand why you have so many uncommented lines (lines beginnig mit ' ) in you code example. I assume that most of those lines would normally not bei uncommented and be part of the working code. Or are there artifacts of the Stack Overflow Editor?
I see a few problems, that might to guide you to a solution.
1) When you use
With fDialog
you let this 'open' until the end of the code (even using a second With in between). I would recommend to set you corresponding 'End With' right after you no longer require it. Remeber (or take note): The
With fDialog
[... something]
' Set the title of the dialog box.
.Title = "Select One or More Files"
is really just a shorthand for
fDialog.Title
(i.e. a "naked" . means, that it has to be appendend to the object in the With) so you could do away with the "With" entirely. IN you example I would set the "End With" right before
If .Show = True Then
and then use
If fDialog.Show = True Then
2) I would set
Set appWord = GetObject(, "Word.Application")
outside your For Each loop (don't forget to take Set appWord = Nothing outside the loop as well). Remember that with GetObject you need an runnig Word-instance, otherwise you might want to use
Set appWord = CreateObject("Word.Application")
or to have it both ways, try to get a Word-object, and if it is not available (i.e. Err.Number = 429) create a new one.
On Error Resume Next
Set appWord = GetObject(, "Word.Application")
If Err.Number = 429 Then
Set appWord = CreateObject("Word.Application")
End If
On Error GoTo 0
3) When working or at least while developping using automation I would always set
objword.Visible = True
so you see error messages or other problems right within Word.
HTH for the next steps (in case you have this problem anymore)
Andreas