Extract multiple html tables via VBA - vba

I've got a URL like this:
http://www.xyz342.net/abc/date_from=24.05.2018 00:00:00&date_to=24.05.2018 00:00:00&abc=2
I've used the following vba code to extract the table into excel:
Sub GetWebTable()
With ActiveSheet.QueryTables.Add(Connection:="URL;http://www.xyz342.net/abc/date_from=24.05.2018 00:00:00&date_to=24.05.2018 00:00:00&abc=2", Destination:=Range("a1"))
.Refresh BackgroundQuery:=False
.SaveData = True
End With
End Sub
Task: I want to extract the table for each day of 2018 automatically until today. Therefore the date in that above given URL has to be changed every time (e.g. http://www.xyz342.net/abc/date_from=20.09.2018 00:00:00&date_to=20.09.2018 00:00:00&abc=2 gives the table for 20.09.2018). How can I do that?
Perfect would be a new worksheet for each day. Every future day should be automatically added.

This should give you some ideas in terms of generating the dates in a loop and concatenating into the URL the current date. It also demonstrates how to add new sheets.
I think there are likely better scraping methods than generating queryTables like this. If you can share HTML for one link (And the lay out is the same for each day) it may be possible to devise a much better approach.
Following on from #Marcucciby2's comment you might also get startdate with something like: startDate = DateSerial(YEAR(Date), 1, 1)
Unless the historic tables are refreshed then you probably only want to run the below once. Then remove the loop and simply have the date generated from dateString = Format$(Date, "dd.mm.yyyy"), or Date-1 to get the prior day. You mention wanting it to be added automatically; You could tie to a change event that is linked to a cell where you select a date from a drop down.
Option Explicit
Public Sub test()
Dim url As String, startDate As Long, endDate As Long, i As Long, dateString As String
startDate = DateValue("2018-01-01")
endDate = CLng(Date)
For i = startDate To endDate
DoEvents
dateString = Format$(i, "dd.mm.yyyy")
url = "http://www.xyz342.net/abc/date_from=" & dateString & " 00:00:00&date_to=" & dateString & " 00:00:00&abc=2"
AddQueryTable url, dateString
Next
End Sub
Public Sub AddQueryTable(ByVal url As String, ByVal dateString As String)
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets.Add
ws.NAME = dateString
On Error Resume Next
With ws.QueryTables.Add(Connection:="URL;" & url, Destination:=ws.Range("a1"))
.Refresh BackgroundQuery:=False
.SaveData = True
End With
On Error GoTo 0
End Sub

Related

Verify if there are conflicts between 2 outlook meeting using VBA

I'm currently working on a macro for outlook, to create meetings from a specific date.
My macro can create, modify, delete meetings.
I would like to check if there are conflicts between meetings when I create one.
I've tried to use AppointmentItem.Conflicts property, but I couldn't have any good results.
Thank you for your help.
D
You can use the Recipient.FreeBusy method which returns free/busy information for the recipient. This following VBA example returns a string of free/busy information with one character for each hour (complete format).
Set myRecipient = myNameSpace.CreateRecipient("Nate Sun")
myFBInfo = myRecipient.FreeBusy(#02/05/2022#, 60, True)
To get information for the current user you may use the NameSpace.CurrentUser property which returns the currently logged-on user as a Recipient object, so may call the FreeBusy method on it.
Note, in case of Exchange accounts you may find the ExchangeUser.GetFreeBusy method helpful. It returns a string representing the availability of the ExchangeUser for a period of 30 days from the start date, beginning at midnight of the date specified.
Sub GetManagerOpenInterval()
Dim oManager As ExchangeUser
Dim oCurrentUser As ExchangeUser
Dim FreeBusy As String
Dim BusySlot As Long
Dim DateBusySlot As Date
Dim i As Long
Const SlotLength = 60
'Get ExchangeUser for CurrentUser
If Application.Session.CurrentUser.AddressEntry.Type = "EX" Then
Set oCurrentUser = _
Application.Session.CurrentUser.AddressEntry.GetExchangeUser
'Get Manager
Set oManager = oManager.GetExchangeUserManager
If oManager Is Nothing Then
Exit Sub
End If
FreeBusy = oManager.GetFreeBusy(Now, SlotLength)
For i = 1 To Len(FreeBusy)
If CLng(Mid(FreeBusy, i, 1)) = 0 Then
'get the number of minutes into the day for free interval
BusySlot = (i - 1) * SlotLength
'get an actual date/time
DateBusySlot = DateAdd("n", BusySlot, Date)
'To refine this function, substitute actual
'workdays and working hours in date/time comparison
If TimeValue(DateBusySlot) >= TimeValue(#8:00:00 AM#) And _
TimeValue(DateBusySlot) <= TimeValue(#5:00:00 PM#) And _
Not (Weekday(DateBusySlot) = vbSaturday Or _
Weekday(DateBusySlot) = vbSunday) Then
Debug.Print oManager.name & " first open interval:" & _
vbCrLf & _
Format$(DateBusySlot, "dddd, mmm d yyyy hh:mm AMPM")
Exit For
End If
End If
Next
End If
End Sub
Also you may try to get all meeting that starts or ends in a specific interval. The Find/FindNext or Restrict method can help with such tasks. Read more about them in the following articles:
How To: Use Restrict method in Outlook to get calendar items
How To: Retrieve Outlook calendar items using Find and FindNext methods

Confusing dd/mm/yyyy and mm/dd/yyyy

I have a VBA script that opens up a bunch of CSV files, and compiles them into one summary report.
However, I'm having a problem where it reads in UK style dates (dd/mm/yyyy), then interprets them as US-style dates when it makes the copy, before display them as UK-style dates again!
So 4th of July in original sheet becomes 7th of April in the summary sheet - verified by changing cell format to display month name.
This is odd, as when you open up the CSV file in Excel, it correctly interprets the UK style date.
Copy is made using code like this
SummarySheet.Cells(Y,X).value = CSVSheet.Cells(W,Z).value
What is going on here?
You did not post the code as to how you are opening your CSV files -- that is the critical area. The dates need to be parsed properly BEFORE being entered on the worksheet. The following code will selects and then opens a file that has UK style dates in a single column, and properly parse them. You will need to adapt it to your particular requirements.
The FieldInfo argument is what does the work. The formatting of the Excel worksheet is "for show" so you can see an unambiguous date.
Option Explicit
Sub OpenUKcsv()
Dim sFile As String
Dim WB As Workbook
Dim WS As Worksheet
sFile = Application.GetOpenFilename()
Workbooks.OpenText Filename:=sFile, DataType:=xlDelimited, comma:=True, other:=False, _
fieldinfo:=Array(1, 4)
Set WB = ActiveWorkbook
Set WS = ActiveSheet
With WS.Columns(1)
.NumberFormat = "dd-mmm-yyyy"
.EntireColumn.AutoFit
End With
End Sub
You could use .Text (text displayed in Excel cell) or .Value2 (value without formatting) instead of .Value (value with formatting).
But I strongly suggest that you set the format of the cells that you use to what you expect to have at the end with .NumberFormat = "mm/dd/yyyy"
Or you could use CDate function :
SummarySheet.Cells(Y,X).value = CDate(CSVSheet.Cells(W,Z).value)
Or use an UDF with DateSerial :
Sub test_CMaster()
MsgBox ParseDate("4/7/15") & vbCrLf & CDate("4/7/15")
End Sub
Function ParseDate(ByVal DateInCell As String, Optional Separator As String = "/") As Date
Dim D() As String
D = Split(DateInCell, Separator)
ParseDate = DateSerial(D(UBound(D)), D(1), D(0))
End Function
Try using the Workbooks.OpenText() method instead and set the Local flag to True
Set csvWB = Workbooks.OpenText(Filename:=myCSVfile, Local:=True)
Here is the MSDN article on this method which says for the Local setting:
Specify True if regional settings of the machine should be used for separators, numbers and data formatting.
Maybe you can convert the CSV files to show dates as numbers, ie. 10th Nov 15 will show as 42318. Or add a separate column where B1 is =DATEVALUE(A1) and work with that.
When you create the summary report, import the numbers and convert them to date using CDate and Format. Something like this:
Sub test()
Range("A2:A4").NumberFormat = "m/d/yyyy"
Range("A2").Value = Format(CDate(Range("A1").Value), "dd.mm.yyyy")
Range("A3").Value = Format(CDate(Range("A1").Value), "mm.dd.yyyy")
Range("A4").Value = Format(CDate(Range("A1").Value), "Long Date")
End Sub
EDIT:
For better formatting (no need for NumberFormat, I think it will use your regional settings right away) and auto-setting the cell format to date-type, use this:
Sub test()
Dim sDate As Date
sDate = CDate(Range("A1").Value)
Range("A2").Value = DateSerial(Year(sDate), Month(sDate), Day(sDate))
End Sub
Result:
References:
http://www.techonthenet.com/excel/formulas/format_date.php
http://www.techonthenet.com/excel/formulas/cdate.php

Why am I getting this error: Object Variable or With block variable not set?

I have found out what causes this error but I cannot pinpoint where it is coming from in my code. I even tested this macro in a separate worksheet in excel and it worked but in this worksheet it is not working. Can anyone guess as to why or offer any workarounds? I put a comment on the line with the error. Assume data is put in correctly.
Private Sub CommandButton1_Click()
Dim startDate As Date, endDate As Date, reason As String, name As String
name = InputBox("Please enter the name of the SLG as appears in column 1 on the worksheet:")
startDate = InputBox("Please enter the start date in MM/DD/YYYY format:")
endDate = InputBox("Please enter the end date in MM/DD/YYYY format:")
reason = InputBox("Please short description for the absence:")
Dim rng1 As Range, columnNumberStart As Integer, rowNumber As Integer, columnNumberEnd As Integer, test1 As String, test2 As String
Worksheets("FY-15 Schedule").Activate
Set rng1 = ActiveSheet.UsedRange.Find(name)
rowNumber = rng1.Row
Set rng1 = ActiveSheet.UsedRange.Find(startDate)
columnNumberStart = rng1.Column 'Says Error is on this line
Set rng1 = ActiveSheet.UsedRange.Find(endDate)
columnNumberEnd = ActiveSheet.UsedRange.Find(endDate).Column
test1 = Cells(rowNumber, columnNumberStart).Address
test2 = Cells(rowNumber, columnNumberEnd).Address
Dim rng2 As Range
Set rng2 = Range(test1, test2)
rng2.Value = reason
End Sub
First, explicitly coerce the date from the inputbox input:
startDate = CDate(InputBox("Please enter the start date in MM/DD/YYYY format:"))
And do the same for the other date field.
Then, there is still possible source of this same error: when the .Find method has returned Nothing to the range object, (e.g., the date is not found/doesn't exist in the sheet) then you are essentially doing Nothing.Column, which is an error.
If the date does not exist in the sheet, this will always raise an error, which you could trap like this, or use GoTo statements to return to the inputbox, etc...
Set rng3 = ActiveSheet.UsedRange.Find(startDate)
If rng3 Is Nothing Then
MsgBox "Start date" & Cstr(startDate) & " not found!", vbInformation
Exit Sub
End If
columnNumberStart = rng1.Column
I figured it out! The problem was this: It was not finding the dates because the dates were being generated by a formula!! My first date was manually typed in but the rest of them were a fill series from the second cell which was A2=A1+1 and all the way down the line. I wanted it that way so the start date could be changed but for some reason excel was not recognizing those as dates!?! How weird?!?!
Problem solved though. What you said was correct about it not finding the date but appearance wise when looking at the spreadsheet it is there in plain sight but when looking at the cells their values were formulas.

Date lookup issue: Unable to get VLookup property of WorksheetFunction class

I've tried almost everything in most of the other similar type questions but I can't seem to solve the runtime error. Help please!
What I want to achieve:
1) My macro is supposed to get date from report summary files that are created every day hence, it requires the user to input which date of report he wants the data from
2) I use the vlookup method to get the data from the relevant row and input it into the central workbook with the macro
3) Every part of the code works except using the date to Vlookup and it will give me this error message
4) I have tested the code using other text based lookup values and the whole macro works (i.e. i looked up the row which has the "Total" value so it looks up "Total" but i require the macro to look up the rows with the date as the look up value)
Addtional Info:
1) In the lookup file, the dates are in the format of "m/d/yyyy" but presented in the format of "dd-mmm-yy" (but i've tried both and they dont work)
Sub GetData()
Dim strDate As Date
strDate = InputBox("Input date of report to retrieve (Format: DD-MM-YYYY)", "Input Date", Format(Now(), "DD-MM-YYYY"))
If IsDate(strDate) Then
'there is some code here not relevant but basically i need to keep manipulating the date throughout the code
With ActiveSheet
Dim XstrDate
Dim Xfile As String
XstrDate = Format(strDate, "mmm DD, YYYY")
Xfile = "C:\...\...\...\Report " & XstrDate & ".xls"
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
Dim returnValue as Variant
Set wb = Application.Workbooks.Open(Xfile)
Set ws = wb.Worksheets("Summary")
Set rng = ws.Range("A:K")
Dim Xdate As String
Xdate = Format(XstrDate, "m/d/yyyy")
returnValue = Application.WorksheetFunction.VLookup(Xdate, rng, 2, 0)
'... more code
remember, i've tried looking up using the text in the same column and it returned me a value. So i suspect the problem lies with the date format or something
Any smart and kind soul want to offer some suggestions here:)
Excel internally stores dates as a Serial Number (e.g. 1/1/2014 = 41640), which you can observe yourself if you enter a date into a cell and then change the format to Number.
With this in mind it's unlikely that a VBA date and an Excel date can be matched using the VLookup function so in my experience the best solution is to convert your date into its serial number and then perform the VLookup on that value instead.
Dim Ndate As Long
Dim returnValue As Date
Ndate = DateSerial(<Year>, <Month>, <Day>)
returnValue = Application.WorksheetFunction.VLookup(Ndate, <rng>, <col>, False)
If you need to construct your DateSerial(...) function from a Date variable in VBA you can use the Year(<date>), Month(<date>), and Day(<date>) functions to break it down into the required components.
Note: I've tried this example in the format .VLookup(DateSerial(2014,1,1),...) and it still causes the same error, hence storing the return value of DateSerial in a numeric variable first.
Happy Coding!
I've taken a different approach and found another solution to this problem.
Rather than use Vlookup, this is the other method that bypass the problem of VLookup date format problem, (having defined vdate in previous statements)
Dim rnge As Range, i As Long
Sheets("Summary").Select
Columns("A:A").Select
Set rnge = Intersect(Selection, ActiveSheet.UsedRange)
If rnge Is Nothing Then
MsgBox "Date Not Found"
GoTo done
End If
For i = rnge.Count To 1 Step -1
If rnge.Cells(i).Value = vdate Then rnge.Cells(i).EntireRow.Copy _
Destination:=ThisWorkbook.Sheets("AnotherSheet").Range("A1")
Next
done:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True

Event(s) for opening the workbook AND worksheets

I'm looking for an elegant solution to trigger an event for opening the workbook as well as opening different worksheets. I don't need seperate operations for each worksheet: they all trigger the same method.
I know I can use the events Workbook_Activate / Workbook_Open and Workbook_SheetActivate at the same time but I don't know if this is 'the official way' to do it. Perhaps there's a way to do this with one event.
I was also wondering if it is relevant in this matter where I put the code. I now have all the code inside "ThisWorkbook" and not in a "Module"...
Here is some code I developed a while ago to ensure that a report my managers use is always opened to the correct tab based on time of day. I house this code in the "ThisWorkbook" module of my VBA.
Sub Workbook_Open()
' Set The Office
Dim begin As String
Dim myNum As String
Dim myNum1 As String
Dim TheDate As String
' Set Date
TheDate = Format(DateTime.Now(), "mm-dd-yy")
Sheets("MORNING").Range("H3").Value = TheDate
Sheets("AFTERNOON").Range("G3").Value = TheDate
'Sheets("EVENING").Range("G3").Value = TheDate
' Select Sheet Based on Time of Day
If Time >= 0.1 And Time < 0.5 Then
Sheets("MORNING").Select
Range("A53").Value = "Report completed by:"
Range("C53").Value = Application.UserName
Range("I53").Value = Date & " " & Time
Range("B27").Select
Call Populate 'Your next code
ElseIf Time >= 0.5 And Time < 0.75 Then
Sheets("AFTERNOON").Select
Range("A54").Value = "Report completed by:"
Range("C54").Value = Application.UserName
Range("I54").Value = Date & " " & Time
Range("C28").Select
Call Populate 'Your next code
End If
End Sub
Notice that I have also added code to auto sign the form output with the userid and update date and time. I hope this helps.
Like others have mentioned: there's no single event to do this. There might be workarounds, but I prefer just using _Open and _SheetActive in that case. Thanks everyone!