I am trying to scrape a table from a website that required logging on, inputting search option, before the table is even displayed. I managed to do the prior, however once the table is displayed I do not know how to get it onto my worksheet.
I have the table HTML location here:
IE.document.querySelector("[id='advanced_iframe']").contentDocument.querySelector("table[id=GridView1]")
and I can get the text from the table via:
IE.document.querySelector("[id='advanced_iframe']").contentDocument.querySelector("table[id=GridView1]").innerText
But I do not know how to get each cell of the table into every cell in my excel sheet ("Sheet1")
Table from the webpage:
Any help is appreaciated.
I can only assume you're using Windows and trying to run the VBA from inside Excel - you don't say otherwise, so here's the simplest solution that doesn't involve looping or dependencies of table format codes
You basically copy/paste the table into Excel using Excel's built in HTML translation tool and Microsoft's Clipboard
First - copy/paste Microsoft's Clipboard API functions into module
Option Explicit
Private Declare Function OpenClipboard Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32.dll" () As Long
Private Declare Function CloseClipboard Lib "user32.dll" () As Long
Private Declare Function IsClipboardFormatAvailable Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function SetClipboardData Lib "user32.dll" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32.dll" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function lstrcpy Lib "kernel32.dll" Alias "lstrcpyW" (ByVal lpString1 As Long, ByVal lpString2 As Long) As Long
Public Sub SetClipboard(sUniText As String)
Dim iStrPtr As Long
Dim iLen As Long
Dim iLock As Long
Const GMEM_MOVEABLE As Long = &H2
Const GMEM_ZEROINIT As Long = &H40
Const CF_UNICODETEXT As Long = &HD
OpenClipboard 0&
EmptyClipboard
iLen = LenB(sUniText) + 2&
iStrPtr = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, iLen)
iLock = GlobalLock(iStrPtr)
lstrcpy iLock, StrPtr(sUniText)
GlobalUnlock iStrPtr
SetClipboardData CF_UNICODETEXT, iStrPtr
CloseClipboard
End Sub
Public Function GetClipboard() As String
Dim iStrPtr As Long
Dim iLen As Long
Dim iLock As Long
Dim sUniText As String
Const CF_UNICODETEXT As Long = 13&
OpenClipboard 0&
If IsClipboardFormatAvailable(CF_UNICODETEXT) Then
iStrPtr = GetClipboardData(CF_UNICODETEXT)
If iStrPtr Then
iLock = GlobalLock(iStrPtr)
iLen = GlobalSize(iStrPtr)
sUniText = String$(iLen \ 2& - 1&, vbNullChar)
lstrcpy StrPtr(sUniText), iLock
GlobalUnlock iStrPtr
End If
GetClipboard = sUniText
End If
CloseClipboard
End Function
Then change your line
IE.document.querySelector("[id='advanced_iframe']").contentDocument.querySelector("table[id=GridView1]").innerText
to assign it to a string variable using outerHTML to get TABLE markup
table_html = IE.document.querySelector("[id='advanced_iframe']").contentDocument.querySelector("table[id=GridView1]").outerHTML
And then copy the table_html to the clipboard, before pasting into your starting cell for your table
SetClipboard table_html
Worksheets("Sheet1").Activate
Range("A1").Select
ActiveSheet.PasteSpecial Format:="Unicode Text", Link:=False, DisplayAsIcon:=False
Here's a tested working example:
Public Sub TestHTMLPaste()
On Error GoTo Err_TestHTMLPaste
Const SiteURL As String = "https://www.grapecity.com/controls/activereports/download-version-history"
Dim IE As Object
Dim BodyHTML As String
Dim FieldStart As Integer
Dim FieldEnd As Integer
Dim TableHTML As String
Set IE = CreateObject("InternetExplorer.Application")
With IE
.Navigate SiteURL
Do While .Busy Or .ReadyState <> 4
DoEvents
Loop
BodyHTML = .document.body.innerhtml
Debug.Print BodyHTML
If InStr(BodyHTML, "<table class=""gctable"">") > 0 Then
Debug.Print "Found it"
TableHTML = .document.querySelector("table[class=gctable]").outerHTML
SetClipboard TableHTML
DoEvents
End If
.Quit
End With
DoEvents
If TableHTML <> "" Then
Worksheets("Sheet1").Activate
Range("A1").Select
ActiveSheet.PasteSpecial Format:="Unicode Text", Link:=False, DisplayAsIcon:=False
DoEvents
Range("A1").Select
Else
MsgBox " No Table HTML found"
End If
Err_TestHTMLPaste:
Set IE = Nothing
End Sub
Related
I made a simple VBA code that go to a link and download a Excel file, the link is an intermediate HTML page which then downloads the file, i just need to access, but now i need to save it. I am a noob at VBA, can anyone help me? Follow the code Bellow
Private pWebAddress As String
Public Declare PtrSafe Function ShellExecute _
Lib "shell32.dll" _
Alias "ShellExecuteA" _
(ByVal hwnd As Long, _
ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
Public Sub NewShell(cmdLine As String, lngWindowHndl As Long)
ShellExecute lngWindowHndl, "open", cmdLine, "", "", 1
End Sub
Public Sub WebPage()
Let pWebAddress = "https://imea.com.br/imea-site/arquivo-externo?categoria=relatorio-de-mercado&arquivo=cup-milho&numeropublicacao=4"
Call NewShell(pWebAddress, 3)
i Have already researched a lot, but none of the ones i have seen had be of help.
UPDATE
With the help of Tim, i sucessfully made the vba code, it was simple.
Dim wb As Workbook
Set wb = Workbooks.Open("PastTheLinkHere")
wb.SaveAs "PastTheDestinationHere"
wb.Close
End Sub
What i really needed was to make the link a direct link, and with help of Tim it was easy. Thank you Tim.
This URL:
https://imea.com.br/imea-site/arquivo-externo?categoria=relatorio-de-mercado&arquivo=cup-milho&numeropublicacao=4
leads to a page with this javascript which builds the final URL:
methods: {
laodMetadata() {
const urlParams = new URLSearchParams(window.location.search);
this.categoria = urlParams.get("categoria");
this.safra = urlParams.get("safra");
this.arquivo = urlParams.get("arquivo");
this.numeropublicacao = urlParams.get("numeropublicacao");
},
async loadData() {
this.loading = true;
const url = "https://publicacoes.imea.com.br";
this.url = url;
if (this.categoria != null)
this.url = this.url + `/${this.categoria}`;
if (this.safra != null) this.url = this.url + `/${this.safra}`;
if (this.arquivo != null) this.url = this.url + `/${this.arquivo}`;
if (this.numeropublicacao != null)
this.url = this.url + `/${this.numeropublicacao}`;
return this.url;
},
The final URL is then:
https://publicacoes.imea.com.br/relatorio-de-mercado/cup-milho/4
So this works and opens the Excel file directly in Excel:
Workbooks.Open "https://publicacoes.imea.com.br/relatorio-de-mercado/cup-milho/4"
You could translate that js into VBA to make a function which would translate the first URL into the second one.
Function tester()
Dim url As String
url = "https://imea.com.br/imea-site/arquivo-externo?" & _
"categoria=relatorio-de-mercado&arquivo=cup-milho&numeropublicacao=4"
Debug.Print MapToDownloadUrl(url)
End Function
Function MapToDownloadUrl(url As String) As String
Dim urlNew As String, dict As Object, e
Set dict = ParseQuerystring(url)
If dict Is Nothing Then Exit Function
urlNew = "https://publicacoes.imea.com.br"
For Each e In Array("categoria", "arquivo", "numeropublicacao")
If dict.exists(e) Then urlNew = urlNew & "/" & dict(e)
Next e
MapToDownloadUrl = urlNew
End Function
'Parse out the querystring parameters from a URL as a dictionary
Function ParseQuerystring(url) As Object
Dim dict As Object, arr, arrQs, e
arr = Split(url, "?")
If UBound(arr) > 0 Then
Set dict = CreateObject("scripting.dictionary")
dict.comparemode = 1 'case-insensitive
arrQs = Split(arr(1), "&")
For Each e In arrQs
If InStr(e, "=") > 0 Then
arr = Split(e, "=")
If UBound(arr) = 1 Then dict.Add arr(0), arr(1)
End If
Next e
Set ParseQuerystring = dict
End If
End Function
I have the below code to open a file location FOLDER, however I would like to open the file itself instead of folder location.
Can someone suggest what should I change in the code.
Private Sub File_locationButton_Click()
Dim filePath
filePath = File_Location
Shell "C:\WINDOWS\explorer.exe """ & filePath & "", vbNormalFocus
End Sub
You can use ShellExecute, so:
Private Sub File_locationButton_Click()
Dim filePath
filePath = File_Location
OpenDocumentFile filePath
End Sub
which calls:
Option Compare Database
Option Explicit
' API declarations for OpenDocumentFile.
' Documentation:
' https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea
'
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hWnd As Long, _
ByVal lpOperation As String, _
ByVal lpFile As String, _
ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long) _
As Long
Private Declare PtrSafe Function GetDesktopWindow Lib "USER32" () _
As Long
' ShowWindow constants (selection).
' Documentation:
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
'
Private Const SwShowNormal As Long = 1
Private Const SwShowMinimized As Long = 2
Private Const SwShowMaximized As Long = 3
' Open a document file using its default viewer application.
' Optionally, the document can be opened minimised or maximised.
'
' Returns True if success, False if not.
' Will not raise an error if the path or file is not found.
'
' 2022-03-02. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function OpenDocumentFile( _
ByVal File As String, _
Optional ShowCommand As Long = SwShowNormal) _
As Boolean
Const OperationOpen As String = "open"
Const MinimumSuccess As Long = 32
' Shall not have a value for opening a document.
Const Parameters As String = ""
Dim Handle As Long
Dim Directory As String
Dim Instance As Long
Dim Success As Boolean
Handle = GetDesktopWindow
Directory = Environ("Temp")
Instance = ShellExecute(Handle, OperationOpen, File, Parameters, Directory, ShowCommand)
' If the function succeeds, it returns a value greater than MinimumSuccess.
Success = (Instance > MinimumSuccess)
OpenDocumentFile = Success
End Function
Have an Access Database that has been upgraded from 2007 32bit to Access 2016 64 bit.
In the one from there is a button to import a csv file for the data.
In the old version it would let you choose the file, but that doesn't work on 2016. This is the vba code for this action that worked in access 2007 32bit version.
Type tagOPENFILENAME
lStructSize As Long
hwndOwner As Long
hInstance As Long
strFilter As String
strCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
strFile As String
nMaxFile As Long
strFileTitle As String
nMaxFileTitle As Long
strInitialDir As String
strTitle As String
Flags As Long
nFileOffset As Integer
nFileExtension As Integer
strDefExt As String
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Declare PtrSafe Function aht_apiGetOpenFileName Lib "comdlg32.dll" _
Alias "GetOpenFileNameA" (OFN As tagOPENFILENAME) As Boolean
Declare PtrSafe Function aht_apiGetSaveFileName Lib "comdlg32.dll" _
Alias "GetSaveFileNameA" (OFN As tagOPENFILENAME) As Boolean
Declare PtrSafe Function CommDlgExtendedError Lib "comdlg32.dll" () As Long
Global Const ahtOFN_READONLY = &H1
Global Const ahtOFN_OVERWRITEPROMPT = &H2
Global Const ahtOFN_HIDEREADONLY = &H4
Global Const ahtOFN_NOCHANGEDIR = &H8
Global Const ahtOFN_SHOWHELP = &H10
' You won't use these.
'Global Const ahtOFN_ENABLEHOOK = &H20
'Global Const ahtOFN_ENABLETEMPLATE = &H40
'Global Const ahtOFN_ENABLETEMPLATEHANDLE = &H80
Global Const ahtOFN_NOVALIDATE = &H100
Global Const ahtOFN_ALLOWMULTISELECT = &H200
Global Const ahtOFN_EXTENSIONDIFFERENT = &H400
Global Const ahtOFN_PATHMUSTEXIST = &H800
Global Const ahtOFN_FILEMUSTEXIST = &H1000
Global Const ahtOFN_CREATEPROMPT = &H2000
Global Const ahtOFN_SHAREAWARE = &H4000
Global Const ahtOFN_NOREADONLYRETURN = &H8000
Global Const ahtOFN_NOTESTFILECREATE = &H10000
Global Const ahtOFN_NONETWORKBUTTON = &H20000
Global Const ahtOFN_NOLONGNAMES = &H40000
' New for Windows 95
Global Const ahtOFN_EXPLORER = &H80000
Global Const ahtOFN_NODEREFERENCELINKS = &H100000
Global Const ahtOFN_LONGNAMES = &H200000
Private Sub cmdImportStudents_Click()
Dim strDirFile As String
strDirFile = GetOpenFile(CurrentDb().Name, "Select Student Import File")
If strDirFile > "" Then
Dim strA1 As String
'---
Open strDirFile For Input As #1
'---
If EOF(1) Then
Close #1
GoTo ErrorImportStudents
Else
'---
Line Input #1, strA1
Close #1
'--- Delete destination table ---
On Error Resume Next
DoCmd.DeleteObject acTable, "STUD_REC"
'--- Import data ---
On Error GoTo ErrorImportStudents
DoCmd.TransferText acImportDelim, "Students (comma)", "STUD_REC", strDirFile
End If
End If
MsgBox "Import Complete!", , "Student Import"
ExitImportStudents:
Exit Function
ErrorImportStudents:
MsgBox "Error(s) occured during 'Student' import!"
Resume ExitImportStudents
End Function
Private Sub cmdExit_Click()
On Error GoTo Err_cmdExit_Click
DoCmd.Close
Exit_cmdExit_Click:
Exit Sub
Err_cmdExit_Click:
MsgBox Err.Description
Resume Exit_cmdExit_Click
End Sub
I have this code to copy files from one location to another in Access 2010 and is working fine. The problem I'm having is copying just the new files to the destination. I do not want to override the files, only copy new files.
Here is my code:
Public Declare Function SHFileOperation Lib "shell32.dll" _
Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
Private Const FO_COPY = &H2
Private Const FO_DELETE = &H3
Private Const FO_MOVE = &H1
Private Const FO_RENAME = &H4
Private Const FOF_ALLOWUNDO = &H40
Private Const FOF_CONFIRMMOUSE = &H2
Private Const FOF_CREATEPROGRESSDLG = &H0
Private Const FOF_FILESONLY = &H80
Private Const FOF_MULTIDESTFILES = &H1
Private Const FOF_NOCONFIRMATION = &H10
Private Const FOF_NOCONFIRMMKDIR = &H200
Private Const FOF_RENAMEONCOLLISION = &H8
Private Const FOF_SILENT = &H4
Private Const FOF_SIMPLEPROGRESS = &H100
Private Const FOF_WANTMAPPINGHANDLE = &H20
Public Type SHFILEOPSTRUCT
hWnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAnyOperationsAborted As Long
hNameMappings As Long
lpszProgressTitle As Long
End Type
Public Sub VBCopyFolder(ByRef strSource As String, ByRef strTarget As String)
Dim op As SHFILEOPSTRUCT
With op
.wFunc = FO_COPY
.pTo = strTarget
.pFrom = strSource
.fFlags = FOF_SIMPLEPROGRESS
End With
'~~> Perform operation
SHFileOperation op
End Sub
I call the subroutine like so
Call VBCopyFolder("O:\fieldticket\pdf\", "\\rwmain01\gis\FieldTicket\")
Here is one option you can try. You will have to iterate through the files though. So, it will potentially be slow over time if you have a large number of files building up.
Public Sub CopyFiles()
Dim fso As Scripting.FileSystemObject
Dim fld As Scripting.Folder
Dim fils As Scripting.Files
Dim fil As Scripting.File
Dim strSourceFolder As String
Dim strDestFolder As String
Dim strFileName As String
On Error GoTo err_Proc
Set fso = CreateObject("Scripting.FileSystemObject")
strSourceFolder = "O:\fieldticket\pdf\"
strDestFolder = "\\rwmain01\gis\FieldTicket\"
If Not fso.FolderExists(strSourceFolder) Then GoTo exit_Proc
Set fld = fso.GetFolder(strSourceFolder)
For Each fil In fld.Files
' Process the file with logic you consider new
If fil.DateCreated > Now - 1 Then
fso.CopyFile fil.Path, strDestFolder & fil.Name
DoEvents
End If
' Or just try to copy it over with overwrite set to false
'fso.CopyFile fil.Path, strDestFolder & fil.Name, False
Next
exit_Proc:
Set fil = Nothing
Set fils = Nothing
Set fld = Nothing
Set fso = Nothing
Exit Sub
err_Proc:
Debug.Print Err.Description
GoTo exit_Proc
End Sub
Does anyone know of a way when using InternetExplorer.Application of using the FileDownload Event and what is possible with it? I'm trying to detect when IE is downloading a file so that when the file download is done the file is handled automatically.
There is a DownloadBegin and a DownloadComplete Events but this look to be talking about when navigating to a URL and not an accual file download.
You should be able to confirm the status of the download process.
Option Explicit
Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Sub DownloadFileAPI()
Dim strURL As String
Dim LocalFilePath As String
Dim DownloadStatus As Long
strURL = "http://data.iana.org/TLD/tlds-alpha-by-domain.txt"
LocalFilePath = "C:\Test\TEST2_tlds-alpha-by-domain.txt"
DownloadStatus = URLDownloadToFile(0, strURL, LocalFilePath, 0, 0)
If DownloadStatus = 0 Then
MsgBox "File Downloaded. Check in this path: " & LocalFilePath
Else
MsgBox "Download File Process Failed"
End If
End Sub
Sub DownloadFile()
Dim WinHttpReq As Object
Dim oStream As Object
Dim myURL As String
Dim LocalFilePath As String
myURL = "http://data.iana.org/TLD/tlds-alpha-by-domain.txt"
LocalFilePath = "C:\Test\TEST_tlds-alpha-by-domain.txt"
Set WinHttpReq = CreateObject("Microsoft.XMLHTTP")
WinHttpReq.Open "GET", myURL, False, "", "" '("username", "password")
WinHttpReq.send
If WinHttpReq.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write WinHttpReq.responseBody
oStream.SaveToFile LocalFilePath, 2 ' 1 = no overwrite, 2 = overwrite
oStream.Close
End If
End Sub