Extract data from excel for input loop in VBA scraping - vba

I am a complete novice in VBA and I'm in way over my head I think but the research necessitates it. I followed a great online tutorial series, which unfortunately didn't help me in solving 1 big problem: Data input.
My goal is to scrape patent data from google patents. To do so, it's pretty convenient that Google patents website is uniquely identified by the patent number. Thus what I want to achieve is the following:
Extract the patent number from a list in excel
Use that number to access the specific webpage
Extract application and publication year of patent, as well as patent number (as check)
Store all in a single excel sheet
Now, I can make 2,3, and 4 work but it's the loop that allows me to extract the patent numbers from excel and put them into my code that I am missing.
Here is the current code:
Private Sub CommandButton4_Click()
Dim obMF As Object
Dim patent As String
Dim grant_date As String
Dim app_date As String
Dim patent_number As String
patent_number = insert.Text ' insert.Text refers to a textbox in my interface
Call gotopat(patent_number, patent, app_date, grant_date)
found.Text = patent
grantdate.Text = grant_date
appdate.Text = app_date
output_row = 1 'Set the output row as 1 (this is where the title is)
Do
DoEvents
output_row = output_row + 1 'Increase output row with 1
Loop Until Sheets("bkcit").Range("B" & output_row) = ""
'Continue loop until that cell ~ Range is blank.
'Once a blank is found, we can put new data in there
'Store data into Worksheet "bkcit"
Sheets("bkcit").Range("B" & output_row) = patent
Sheets("bkcit").Range("C" & output_row) = grant_date
Sheets("bkcit").Range("D" & output_row) = app_date
In this code, found.Text, grantdate.Text, and appdate.Text are sourced from the scraping function which works perfectly. The important things about that function are:
Function gotopat(patent_number As String, patent As String, app_date As String, grant_date As String)
' A Bunch of other stuff
obMF.Navigate ("http://www.google.com/patents/US" & patent_number & "?")
'All the scraping code'
So, I want to replace the patent_number = insert.Text by a loop that looks in my excel sheet bkcit, column A and basically loops through all the unique patent numbers. I tried
input_row = 1
Do
DoEvents
input_row = input_row + 1
Range("C" & input_row) = patent_number
Loop Until Sheets("bkcit").Range("A" & input_row) = ""
But this seems to delete the first patent number in cell A2 and nothing more.
I'm thinking I'm pretty close to a working solution but your help would be fantastic, as always!
Thanks in advance
Simon

If I understand correctly, you have a column of patent numbers like this:
And you want to loop through each number and do something to it. Try this:
Sub loopPatents()
Dim patentNumber As Range
Dim patentRange As Range
Set patentRange = Worksheets(1).Range("A2:A10")
For Each patentNumber In patentRange
MsgBox ("Patent number: " & patentNumber)
'Do your stuff with the patent number here
Next patentNumber
End Sub

Related

Excel VBA - Compile Error - Object Required

This is my first post to this wonderful forum . I am new to VBA and have been writing my first meaningful macro beside doing some practice while learning.
While the WIP code is reproduced below, let me give you a background.
Have a a sheet to calculation investment maturity based on various inputs like Term of Payment and term of Maturity.
This sheet has all the formule in place to compute the maturity value.
Now on sheet 2, I am creating a matrix structure with a intersection of payment term and term of maturity. For ex combination of 1 Yr of Payment term with maturity ( 1...25) and next Payment term and so on.
I am writing a macro which will pick up the user choice from sheet 1 and then loop the macro in matrix and capture the result and paste it to sheet two .
I am still far away from what i have to achive but got a code in first few line of selecting and setting the payment term and maturity terms
Error is Compile error- Object required. I am not able to figure out what it it. WIP code is reproduced below
Private Sub Simulation_Click()
Dim PPT As String
Dim Term As String
MsgBox (" The Programme is starting now")
Set PPT = Workbooks("himanshu.xlsm").Worksheet("Sheet1").Range("G2").Value
Set Term = Workbooks("himanshu.xlsm").Worksheet("Sheet1").Range("G3").Value
For PPT = 1 To PPT
For Term = 1 To Term
' Do something here
Next Term
Next PPT
End Sub
Please help
EDIT # 1- September 19,2017, 3.10 AM IST
Hi Experts,
Finally my first VBA code is running . Its slow but its running. One last problem
I have issue in Code line "Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2").Copy Workbooks("himanshu.xlsm").Sheets("What if").Cells(cols, Rowsh)" where while to source carries the right value( checked in debug Mode) but when it is pasted to target, it is pasted as 0. When I checked the target sheet , somehow it is showing me a formula (= Max( R1C1 :X1Y1). Please note that from where I am copyiong the value ( Source) , its a excel calculation which is arrived as a formula of selecting max of col J . I suspect that code is copying the formula instead of value. Please advice
Option Explicit
Sub macro21()
'MsgBox ("Start")
Dim i As Integer, j As Integer
Dim PPT As Integer
Dim Term As Integer
Dim pptrange As Range ' Address of the Cell where PPT is maintained in Sheet 1
Dim termrange As Range ' Address of the Cell where Term is maintained in Sheet 1
Dim cols As Integer
Dim Rowsh As Integer
PPT = 3
Term = 5
cols = 3
Rowsh = 3
For i = 1 To PPT
For j = 1 To Term
Set pptrange = Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("G2") ' Set pptrange and termrange locations
Set termrange = Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("G3") ' Set pptrange and termrange locations
pptrange.Value = i
termrange.Value = j
***Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2").Copy Workbooks("himanshu.xlsm").Sheets("What if").Cells(cols, Rowsh)***
' MsgBox ("Value is " & Cells(cols, Rowsh).Value)
MsgBox ("Value is " & Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2"))
If j < Term Then
cols = cols
Rowsh = Rowsh + 1
End If
Next j
cols = cols + 1
Rowsh = 3
Next i
End Sub
I have issue in Code line "Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2").Copy Workbooks("himanshu.xlsm").Sheets("What if").Cells(cols, Rowsh)" where while to source carries the right value( checked in debug Mode) but when it is pasted to target, it is pasted as 0. When I checked the target sheet , somehow it is showing me a formula (= Max( R1C1 :X1Y1). Please note that from where I am copyiong the value ( Source) , its a excel calculation which is arrived as a formula of selecting max of col J . I suspect that code is copying the formula instead of value. Please advice
PPT is a string so you should use:
PPT = ...
and not
Set PPT =
Set is used to assign object variables such as workbooks, worksheets, etc.
Edit: as Jeeped mentioned in his comment you have to change data type. You cannot use string in a loop like that. Change Term and PPT to Integer or Long.

Returning a quick statistical info for a cell as a comment

I have a long list of data on an excel table. This data includes detail information of each order in several rows. There is a column shows the status of each row. Also, I have a dashboard which just lists out the order names. I want the users to be able to see a short statistical info of each book as a comment or when they mouse over the cell, if possible or as a cell data. The info could be something like underneath sample in 3 or 4 row. (The number of items is the count of rows with the same status)
5 issued item
3 shortage items
2 Done items
X other
If you just give me the general idea it would be great.
I think I have to use a collection procedure, something like "scripting dictionary" but I have no experience using them. I know how to do that by putting a case statement after if clause inside a loop, but I am looking for a smarter way. you can find some pictures and a sample data below: sample pictures
For the record, I came to this answer from one of friends in MrExcel froum. Hope you find it usefull.
The just difference is, I was looking for a momentum reply just for an active cell, but this code, provide all the information for all the order names as a comment. but it is very easy to adjust!
Sub UpdateComments()
Dim c As Variant, strComment As String
Dim intISSUED As Integer, intSHORTAGE As Integer
Dim tblDATA As ListObject, tblDASH As ListObject
Set tblDATA = Application.Range("TBL.data").ListObject 'adjust Table Name
Set tblDASH = Application.Range("TBL.dash").ListObject 'adjust Table Name
For Each c In tblDASH.ListColumns("W/B").DataBodyRange
strComment = ""
intISSUED = Application.CountIfs(tblDATA.ListColumns("Work Book").DataBodyRange, c, tblDATA.ListColumns("Stage").DataBodyRange, "Issued")
strComment = strComment & Chr(10) & "Issued: " & intISSUED
intSHORTAGE = Application.CountIfs(tblDATA.ListColumns("Work Book").DataBodyRange, c,tblDATA.ListColumns("Stage").DataBodyRange, "Shortage")
strComment = strComment & Chr(10) & "Shortage: " & intSHORTAGE
' ADDITIONAL 'STAGES' HERE
' OR put 'stages' in array to condense code
With Sheets(tblDASH.Parent.Name).Range(c.Address)
If .Comment Is Nothing Then
.AddComment
.Comment.Visible = False
End If
.Comment.Text Text:=Mid(strComment, 2)
End With
Next c
End Sub

Searching names with inconsistent formatting

I built a sub that iterates over a sheet of business transactions for the day and addresses and attaches PDF receipts for our customers. Some customers work for the same firm, but are treated as different entities so they each receive their own email receipts. Folks from this particular firm are only identifiable as a team by their email handle, which is how I have been matching what receipts go to which email handles for which individuals.
Problem:
The problem I've encountered is that in the contacts master list (holds all of the contact information) the names are listed as first name then last name (I.E. John Snow) and on the occasion one of the external systems that information is pulled from lists the names as Last name then first name (Snow John), which isn't found by my current code. I know I could probably use InStr but to me that's a bit sloppy and the information contained in these receipts are extremely confidential. I'm struggling to come up with an consistent way to find the name regardless in a neat and eloquent way.
Possible solution I thought of was to split the names and store them into an array and then compare the different index places, but that seems inefficient. Any thoughts?
Current Code that is insufficient Note: This is only a small function from the main routine
Private Function IsEmpSameFirm(empName As String, firmEmail As String, firmName As String) As Boolean
'Finds separate employee email and compares to current email to find if same distribution
Dim empFinder As Range, firmFinder As Range
Dim columnCounter As Long
columnCounter = 1
While firmFinder Is Nothing
Set firmFinder = contactsMaster.Columns(columnCounter).Find(firmName)
columnCounter = columnCounter + 1
Wend
Set empFinder = contactsMaster.Rows(firmFinder.Row).Find(empName)
If empFinder Is Nothing Then
IsEmpSameFirm = False
ElseIf empFinder.Offset(0, 1).Value = firmEmail Then
IsEmpSameFirm = True
Else
IsEmpSameFirm = False
End If
End Function
Short answer: It is not possible
Middle answer: This implies a reasoning:
- You loop through your memories to recall which of the 2 gaven "Strings" is a name and which one is a last name. If you wish the PC to do the same, you'd need to "teach" it that -write a DataBase which contains every last name you know and if it's found there then it's a last name-
Long Answer:
What I'd do is split the text in columns, do a filter for each one and then analyze them "manually", this function may help you to split the string
Function RetriveText(InString As String, ChrToDivide, Position As Long)
On Error GoTo Err01RetriveText
RetriveText = Trim(Split(InString, ChrToDivide)(Position - 1))
If 1 = 2 Then '99 If error
Err01RetriveText: RetriveText = "Position " & Position & " is not found in the text " & InString
End If '99 If error
End Function
IE:
A1 =John Smith
B1 =RetriveText(A1," ",1) 'Result: John
C1 =RetriveText(A1," ",2) 'Result: Smith
Edit: Just realized that you are trying to send by email, are they contacts in Outlook? If so, why not to check them there? Try this function
Public Function ResolveDisplayName(sFromName) As Boolean
'----------------------------------------------------------------------------------
' Procedure : ResolveDisplayNameToSMTP
' Author : Sue Mosher - updated by D.Bartrup-Cook to work in Excel late binding.
'-----------------------------------------------------------------------------------
Dim olApp As Object 'Outlook.Application
Dim oRecip As Object 'Outlook.Recipient
Dim oEU As Object 'Outlook.ExchangeUser
Dim oEDL As Object 'Outlook.ExchangeDistributionList
Set olApp = CreateObject("Outlook.Application")
Set oRecip = olApp.Session.CreateRecipient(sFromName)
oRecip.Resolve
If oRecip.Resolved Then
ResolveDisplayName = True
Else
ResolveDisplayName = False
End If
End Function

VBA - Creating a Data Sheet from a User Form

I'm hoping that someone can help me with my issue. I've searched this site for the correct coding for my spreadsheets, but nothing seems to work.
I have two spreadsheets: I have a front facing form (Sheet1) where the user can input information. Once the user is done inputting their information, they will press a button which will transfer the data to a large data spreadsheet ("Records"). Once the data copies from Sheet1 to Records, I want Sheet1 to clear (so that the next user has a blank form to work from). Additionally, when a new user inputs information, I want that information to go on a line below the previous user's data input on Records.
I hope that this makes sense... This is the code that I'm using now, which doesn't populate anything in "Records" (I've clearly made a mess of this).
Sub BUTTON()
Dim refTable As Variant, trans As Variant
refTable = Array("c = e6", "d = e7", "e=e8", "f=e9", "g=e10")
Dim Row As Long
Row = Worksheets("Records").UsedRange.Rows.Count + 1
For Each trans In refTable
Dim Dest As String, Field As String
Dest = Trim(Left(trans, InStr(1, trans, "=") - 1)) & Row
Field = Trim(Right(trans, Len(trans) - InStr(1, trans, "=")))
Next
End Sub
Does anyone have any advice for coding? Please let me know!
Try this code.
The key bit is to set up the fields as per the order you want them to appear in worksheets("Records") in columns A to V.
For example, in my example e6 maps to column A, e7 to column B etc.
Sub MapInputToColumn()
Dim fields As Range, rw As Integer, col As Integer
Set fields = Union(Range("e6"), Range("e7"), Range("e8"), Range("e9"), Range("e10"))
rw = Worksheets("Records").UsedRange.Rows.Count + 1
For col = 1 To fields.Count
Worksheets("Records").Cells(rw, col) = fields(col, 1)
Next col
fields.ClearContents
End Sub

Is it possible to add cases to a Select Case based on the number of entries in a table?

I've been messing around with VBA in Excel a bit recently; and as a small project for myself, I'm trying to create a "draw names from a hat" sort of macro.
I began by generating a random number, and then choosing which entry from a Table (i.e. ListObject) would be selected using a case statement. The problem with this is that it only works of the number of Table entries is always the same.
So my question (probably a ridiculous one) is: is it possible at all to generate a dynamic 'Select Case' block, where the number of cases on the block is based on the number of entries in the Table?
Thanks.
-Sean
Edit: To clarify: what I am trying to do, exactly, is this:
I generate a random number, i, from 1 to n=10*(number of Table entries). After this, I want to display, in a cell, one of the table entries based on the random number.
Ideally, the code would work similarly to this:
if i = 1 to 10 then choose event 1
if i = 11 to 20 then choose event 2
if i = 21 to 30 then choose event 3
...
if i = (n-9) to n then choose event (n/10)
I hope this helps to clarify the goal of the code.
From our comments here is something you can use:
Sub random()
Dim used_rows As Integer
Dim random As Integer
Dim cell_array() As Integer
used_rows = Sheet1.UsedRange.Rows.Count
ReDim cell_array(used_rows)
For i = 1 To used_rows
cell_array(i - 1) = Cells(i, 1)
Next
random = Int(Rnd * (used_rows))
MsgBox cell_array(random)
End Sub
You can go ahead and change MsgBox to whatever you like, or set like Cell(1,4).Value = cell_array(random), or however you'd like to proceed. It will be based off the number of rows used. Though depending on how you implement your spreadsheet the code might have to be changed a bit.
Here's the update code from the suggestions from the comments. Also remember to use Randomize() in your form initialization or WorkBook Open functions.
Sub random()
Dim used_rows As Integer
Dim random As Integer
'Multiple ways to get the row count, this is just a simple one which will work for most implementations
used_rows = Sheet1.UsedRange.Rows.Count
random = Int(Rnd * (used_rows))
'I use the variable only for the reason that you might want to reference it later
MsgBox Cells(random, 1)
End Sub
This assumes that by "table" you mean "Table with a capital T", known in VBA as a ListObject:
Sub PickRandomTens()
Dim lo As Excel.ListObject
Dim ListRowsCount As Long
Dim RandomNumber As Long
Dim ListEvent As String
Dim Tens As Long
Set lo = ActiveSheet.ListObjects(1)
ListRowsCount = lo.DataBodyRange.Rows.Count
RandomNumber = Application.WorksheetFunction.RandBetween(10, ListRowsCount * 10)
ListEvent = lo.ListColumns("Data Column").DataBodyRange.Cells(Int(RandomNumber / 10))
MsgBox "Random number: " & RandomNumber & vbCrLf & _
"Event: " & ListEvent
End Sub