VBA macro needed for pulling particular option value of a webpage - excel

I currently have the following macro to load a webpage:
Sub OOS_Query()
'This together with the True value at the end will tell the macro to not update the screen until it reaches a point that I want it to show updates again
Application.ScreenUpdating = False
ActiveWorkbook.Connections("Connection1").Delete
Sheet2.Range("A:C").Clear
With Sheet2.QueryTables.Add(Connection:= _
"URL;http://[ommitted on purpose]id=42908", Destination:=Sheet2.Range("$A$1"))
.FieldNames = True
.PreserveFormatting = True
.RefreshOnFileOpen = True
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.RefreshPeriod = 5
.WebSelectionType = xlSpecifiedTables
.WebFormatting = xlWebFormattingNone
.WebTables = "1,2"
.WebPreFormattedTextToColumns = True
.WebConsecutiveDelimitersAsOne = True
.WebSingleBlockTextImport = False
.WebDisableDateRecognition = False
.WebDisableRedirections = False
.Refresh BackgroundQuery:=True
End With
Application.ScreenUpdating = True
End Sub
As you can see the webpage has an "id" value that is constantly changing as it queries a database. That value looks as follows on the source of the webpage:
Date <select name="id">
<option value='43032' >2017-05-13 05:00:01</option>
<option value='43031' >2017-05-13 04:45:02</option>
<option value='43030' >2017-05-13 04:30:01</option>
<option value='43029' >2017-05-13 04:15:02</option>
...
<option value='43004' >2017-05-12 22:00:01</option>
I am looking for a way to integrate in the code to be able to pull the website with whatever id it has, as long as the time is between 21:58:00 and 22:02:00; for whatever the current date is. The way this is normally done is by accessing the website and selecting out of a drop down menu the date/time that we want to query and then copy pasting the website into the section of the code above.
If I could make it do that automatically, it will remove me having to edit the code everyday.
Thanks in advance!

I adjusted the code to query the webpage but to extract the ID value from a cell in a sheet of my designation. Then I also added a couple more things on the code.
The ID is easy to figure out since I need it for every day at 10pm (22hr), then I know whatever value is in there is going to be added the number 96. 96 = the amount of times the value changes in a 24 hr period given that they change every 15 mins (4 times in 1 hr). So 4 times 24 gives me 96, which I add to whatever the ID was today at 10pm.
Then I just build 2 columns one with the IDs taking into account what I said above, and the other column with dates. Then I built an array formula on a dummy cell that matches based on the day which gives me the id value im looking for. Code looks like this:
Sub OOS_Query()
Application.ScreenUpdating = False
ActiveWorkbook.Connections("Connection1").Delete
Sheet2.Range("A:C").Clear
Dim wb As Workbook
Dim src As Worksheet
Dim url As String
Dim symbol As String
Set wb = ThisWorkbook
Set src = wb.Sheets("OldTime")
symbol = src.Range("K2")
url = "URL;[omitted on purpose]="
url = url & symbol
With Sheet2.QueryTables.Add(Connection:= _
url, _
Destination:=Sheet2.Range("$A$1"))
.FieldNames = True
.PreserveFormatting = True
.RefreshOnFileOpen = True
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.RefreshPeriod = 5
.WebSelectionType = xlSpecifiedTables
.WebFormatting = xlWebFormattingNone
.WebTables = "1,2"
.WebPreFormattedTextToColumns = True
.WebConsecutiveDelimitersAsOne = True
.WebSingleBlockTextImport = False
.WebDisableDateRecognition = False
.WebDisableRedirections = False
.Refresh BackgroundQuery:=True
End With
Application.ScreenUpdating = True
End Sub
Excell formula:
INDEX(I:I,MATCH(TODAY(),J:J,0))
Hope this helps anyone out there that may have similar questions.

Related

Find and replace text from excel vba in a word document

I am trying to create multiple word documents all based on one template, currently I can open the template word doc and save it as the file name I want which gets pulled from a table in excel. What I want to do is replace the text "##Title##" in the template before I save it as a new document. This is the code I have which does not replace any text:
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open(reportTemplate)
objDoc.Content.Find.Text = "##Title##"
objDoc.Application.Selection.Find.Text = "##Title##"
objDoc.Application.Selection.Find.Execute
objDoc.Application.Selection.Find.Replacement.Text = clients(i)
objDoc.Application.Selection.Find.Execute
objWord.Visible = True
objDoc.SaveAs (fileName)
Any help would be great, thanks!
You don't need to do an execute when searching (only for replacing), and a common answer here would be :
With objDoc.Content.Find
.Text = "##Title##"
.Replacement.Text = clients(i)
.Forward = True
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceOne
End With
The microsoft official documentation also has good examples

QueryTables.Add(Connection) ERROR , Expected '='

So, first of all, i am not familiar with VBA. I've been trying to learn VBA because at my job that's what drives the backbone of our database and our excel workflow (although no one at my division seems to know how any of it works). And i've been trying to write a macro that could automate some of the work i have to do, namely: Importing CSV files into an excel to process them. I've been trying to approach this problem step by step, by dividing into smaller subsets of problems.
So I have been able to add a query into my excel, that allows it to look into a folder to see which files are in there. This allows the macro to 'see' different file paths and filenames.
What i am trying to accomplish now is to have the macro loop through all the files it can see in the folder, and import them to a sheet called 'output'.
No matter what i've tried, and how much research i did, i can't figure out the import macro. It keeps giving me a compile error that it expects '='
(I know that the macro is able to read the filenames etc correctly, because i have created a sub that makes it 'log' whatever it reads, to test its ability to differentiate between file types)
Dim ImportFolder As String
Dim ImportRow As Range
Dim ImportFilename As Range
Dim ImportFilenameS As String
Dim ImportAccessDate As Range
Dim ImportFilePath As Range
Dim ImportExtension As Range
Dim ImportRange As Range
Dim ImportVar As Integer
Dim ImportLength As Integer
Dim L
Dim LogRow As Range
Dim LogFilename As Range
Dim LogAccessDate As Range
Dim LogFilePath As Range
Dim LogStatus As Range
Dim LogReason As Range
Dim OutputFolder As String
Dim OutputRange As Range
Sub FileTypeController()
Set ImputFolder = "H:\BLM.Workflow\CSV.Workflow-Input\"
Set ImportExtension = ThisWorkbook.Worksheets("Import").Range("B2")
Set ImportFilename = ThisWorkbook.Worksheets("Import").Range("A2")
Set ImportAccessDate = ThisWorkbook.Worksheets("Import").Range("C2")
Set ImportFilePath = ThisWorkbook.Worksheets("Import").Range("G2")
Set LogFilename = ThisWorkbook.Worksheets("Log").Range("A2")
Set LogAccessDate = ThisWorkbook.Worksheets("Log").Range("B2")
Set LogFilePath = ThisWorkbook.Worksheets("Log").Range("C2")
Set LogStatus = ThisWorkbook.Worksheets("Log").Range("D2")
Set LogReason = ThisWorkbook.Worksheets("Log").Range("E2")
Set ImportRange = ThisWorkbook.Worksheets("Import").Range("A:A")
ImportVar = WorksheetFunction.CountA(ImportRange)
ImportLength = (ImportVar - 1)
For L = 1 To ImportLength
If ImportExtension.Value = ".csv" Or ImportExtension.Value = ".txt" Then
Call CSVToOutput Else Call ExtensionTypeFailedImport
Set ImportExtension = ImportExtension.Offset(1, 0)
Set ImportFilename = ImportFilename.Offset(1, 0)
Set ImportAccessDate = ImportAccessDate.Offset(1, 0)
Set ImportFilePath = ImportFilePath.Offset(1, 0)
Set LogFilename = LogFilename.Offset(1, 0)
Set LogAccessDate = LogAccessDate.Offset(1, 0)
Set LogFilePath = LogFilePath.Offset(1, 0)
Set LogStatus = LogStatus.Offset(1, 0)
Set LogReason = LogReason.Offset(1, 0)
Next
ThisWorkbook.Worksheets("Log").Activate
End Sub
Sub CSVToOutput()
ImportFilenameS = "TEXT;" & ImportFilename.Value
Set OutputRange = ThisWorkbook.Worksheets("Output").Range("A1")
'Application.CutCopyMode = False
With ThisWorkbook.Worksheets("Output").QueryTables_
.Add(Connection:= ImportFilenameS,Destination:= OutputRange)
.Name = "Importfilename"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 1252
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
Call SuccessfulImport
End Sub
It's still a first draft, so i haven't taken the time to clean it up a little yet.
Apologies if the code is trash, but, i'm giving it my all ;-)
At first I spot an error here:
Set ImputFolder = "H:\BLM.Workflow\CSV.Workflow-Input\"
Reason: you only use the reserved word Set with objects, and in this case, you are just assigning a value to a string variable.
Also, I didn't see that variable defined anywhere. Maybe you meant to use this one:
Dim ImportFolder As String
Those facts aside, I suggest that you look into Power Query. If you have Excel 2010, 2013 you can download it as an add-in or if you have 2016-2019 is already available in the Ribbon's Data tab.
Check Matt’s tutorial on how to combine files from a folder here

VBA Replace From Excel to Word

I am using VBA codeI picked up online to essentially input a couple of sections and have Excel then edit a Word template, replacing <oaccount> for the inputted account number and <date> for the date of something, etc.
The issue I am facing is that when using it, the core value of the cell is being inputted and not what you see... For example, I have everything working except the date and the $ amount because when it replaces <date> and <amount> they show up as "240419" and "3450" when inputting 24/04/2019 and $3,460.00 respectively.
I want to find out how to get Excel to replace the key words with the actual displayed value of Excel.
Below is what I am using to do this:
Option Explicit
Public Sub WordFindAndReplace()
Dim ws As Worksheet, msWord As Object
Set ws = ActiveSheet
Set msWord = CreateObject("Word.Application")
With msWord
.Visible = True
.Documents.Open "F:\Test folder\TestFolder\Test.docx"
.Activate
With .ActiveDocument.Content.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "CName"
.Replacement.Text = ws.Range("C1525").Value2
.Forward = True
.Wrap = 1 'wdFindContinue (WdFindWrap Enumeration)
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=2 'wdReplaceAll (WdReplace Enumeration)
End With
.Quit SaveChanges:=True
End With
End Sub
Have you tried using the Format function on the replacement line? There's a page with a description of it here. You can also try converting it to a string in that same line using the CStr() function.
It would look something like this if you use format:
.Replacement.Text = Format(ws.Range("C1525").Value2,"dd/mm/yyyy")
If you use the string conversion it would look like this:
.Replacement.Text = CStr(ws.Range("C1525").Value2)

Text retrieved on multiple rows on Excel VBA

I'm a kind of new to Excel VBA. Here's the problem:
Given a identifier, I want to retireve some text from a web page. Ideally I want to store the text of the page in a single cell. I created a function that creates a QueryTable but, sometimes, the retrieved text is copied on multiple rows.
Is there a way to place all the text on a single cell?
Here's the code of my function:
Function Articolo(myRange As Range, code As String)
Dim myURL As String
Dim myName As String
myURL = "URL;http://techstore.runner.it/feed/dettagli_csv.php?codcli=111367&pwd=03142110786&sku=" & code
myName = "dettagli_csv.php?codcli=111367&pwd=03142110786&sku=" & code
With ActiveSheet.QueryTables.Add(Connection:= _
myURL _
, Destination:=myRange)
.Name = myName
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = False
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlOverwriteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = False
.RefreshPeriod = 0
.WebSelectionType = xlEntirePage
.WebFormatting = xlWebFormattingNone
.WebPreFormattedTextToColumns = False
.WebConsecutiveDelimitersAsOne = False
.WebSingleBlockTextImport = True
.WebDisableDateRecognition = False
.WebDisableRedirections = False
.WebConsecutiveDelimitersAsOne = True
.Refresh BackgroundQuery:=False
End With
End Function
As test you can use 8E4374 as code
Thanks for your help!
Querytables are often slow and cumbersome. If you use one of the httprequest objects instead it's much quicker and you have more control over how to parse the response. Below is basic example that doesn't manage sessions or check if the page is cached.
Option Explicit
Sub test()
Dim rng As Range
Dim code As String
Set rng = Sheet1.Range("A1")
code = "8E4374"
Articolo rng, code
End Sub
Sub Articolo(myRange As Range, code As String)
Dim myURL As String
Dim myName As String
myURL = "http://techstore.runner.it/feed/dettagli_csv.php?codcli=111367&pwd=03142110786&sku=" & code
myRange.Value = ExecuteWebRequest(myURL)
End Sub
Function ExecuteWebRequest(ByVal url As String) As String
Dim oXHTTP As Object
Set oXHTTP = CreateObject("MSXML2.XMLHTTP")
oXHTTP.Open "GET", url, False
oXHTTP.send
ExecuteWebRequest = oXHTTP.responseText
Set oXHTTP = Nothing
End Function
EDIT: the above code is designed to run as a Sub rather than a UDF. Since a UDF cannot affect other cells the only option is to return the string to the calling cell or call set up the code to run as either an event or from a control (eg a button)
Below is an example UDF, it's called from Excel using =Articolo(C1) where C1 is any cell containing the required code eg 8E4374
Option Explicit
Function Articolo(ByVal code As String) As String
Dim myURL As String
myURL = "http://techstore.runner.it/feed/dettagli_csv.php?codcli=111367&pwd=03142110786&sku=" & code
Articolo = ExecuteWebRequest(myURL)
End Function
Function ExecuteWebRequest(ByVal url As String) As String
Dim oXHTTP As Object
Set oXHTTP = CreateObject("MSXML2.XMLHTTP")
oXHTTP.Open "GET", url, False
oXHTTP.send
ExecuteWebRequest = oXHTTP.responseText
Set oXHTTP = Nothing
End Function
Also, as this is making http requests, everytime you force a full re-calc your UDF's will also re-calc which is probably not what you want as you could be making hundreds or thousands of requests. I would suggest running it once only from a defined loop such as
For Each code in Listofcodes : <Download Page> : Next code
It looks like the data coming from that URL has carriage return and line feeds embedded in it. That's why it's separating into different cells in excel.
One solution would be to run VBA code to do the query, strip out the carriage return/line feed characters and then put the results into a cell. The problem would be that you'd have to run the code to update, rather than excel taking care of the refreshes.
A simpler answer might be to add another cell with a formula like this:
=A1&" "&A2&" "&A3&" "&A4

Excel VBA: Looped Web Queries

I have a list of 100,000 URLs that I need to parse via an API call. I've sorted them into a list of 600+ concatenated strings, each containing 200 URLs - ready to be parsed.
I've written the code below to loop the process, places the returned information about the URLs in the last row of column C, one at a time. However, my loop seems to be broken and I don't know why (looking at it too long) but I suspect it's a rookie mistake. After doing the first two concatenated strings (400 URLs, it starts to rewrite the information from around row 200, processing only the first string.
The code is below and any help will be greatly appreciated. Regrettably, I can't share the URL that I'm attempting to parse because it's a propriety system built by my employers and isn't for public use.
Sub APIDataProcess()
Dim lURLsLastRow As Long
Dim lDataSetLastRow As Long
Dim rngURLDataSet As Range
Dim sURLArray As String
Dim lURLArrayCount As Long
Dim rngArrayCell As Range
lURLsLastRow = Cells(Rows.Count, 1).End(xlUp).Row
lDataSetLastRow = Cells(Rows.Count, 3).End(xlUp).Row
Set rngURLDataSet = Range("A1:A" & lDataSetLastRow)
lURLArrayCount = Range("B1").Value ' placeholder for count increments
sURLArray = Range("A" & lsURLArrayCount).Value
For Each rngArrayCell In rngURLDataSet
If lsURLArrayCount <= lURLsLastRow Then
With ActiveSheet.QueryTables.Add(Connection:="URL;http://test.test.org/test.php", Destination:=Range("C" & lDataSetLastRow))
.PostText = "urls=" & sURLArray
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = False
.RefreshStyle = xlOverwriteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.WebSelectionType = xlEntirePage
.WebFormatting = xlWebFormattingNone
.WebPreFormattedTextToColumns = True
.WebConsecutiveDelimitersAsOne = True
.WebSingleBlockTextImport = False
.WebDisableDateRecognition = False
.WebDisableRedirections = False
.Refresh BackgroundQuery:=False
End With
lURLArrayCount = lURLArrayCount + 1
Range("B1").Value = lURLArrayCount
Application.Wait Now + TimeValue("00:01:00")
Else
Exit Sub
End If
Next rngArrayCell
End Sub
You probably solved your own problem long ago but since the question is still open I will have a go.
I assume the intention is that B1 is initially 1 and is then stepped after each row is processed. This would allow you to stop the macro and carry on from where you had got to on the previous run.
But you do not use B1 or lURLArrayCount like that. The range you examine is always A1 to Amax. You step lURLArrayCount and store it in B1 but its value is not used within the loop.
You set sURLArray outside the loop but use it within.
The loop is For Each rngArrayCell but you never use rngArrayCell.
You do not step lDataSetLastRow after a result has been added.

Resources