Webscrape into Visual Studio VB Form - vb.net

I've got a form that looks like the following:
I would like to simply enter the stock, click the get price button, have the button return the price it scraped.
I'm experienced with Excel VBA and how to scrape but not so much how it translates into Visual Studio (VB language)
Below is what I've got for the form so far. I attempted to add the HTML document and Internet controls methods already. So far I can get it to successfully open and shut internet explorer--I just can't get it to scrape anything. It just errors out, and I can't dim internet explorer as an HTML object. Below is the code so far...
Public Class Form1
Dim stockBox As Single
Dim price As Single
Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click
End Sub
Private Sub Label2_Click(sender As Object, e As EventArgs) Handles Label2.Click
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
End Sub
Private Sub Label3_Click(sender As Object, e As EventArgs) Handles Label3.Click
End Sub
'Private Function READYSTATE_COMPLETE() As Object
'Throw New NotImplementedException()
' End Function
' Private Sub DoEvents()
'Throw New NotImplementedException()
' End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ie As Object
Dim px As Single
ie = CreateObject("InternetExplorer.Application")
With ie
.Visible = True
.navigate("http://finance.yahoo.com/q?s=" & (TextBox1.Text))
'Do
' DoEvents
'Loop Until ie.readyState = READYSTATE_COMPLETE
'Dim doc As HtmlDocument
'doc = ie.document
While ie.readyState <> 4
End While
On Error Resume Next
px = ie.GetElementById("yfs_l84_" & (TextBox1.Text)).InnerText
ie.Quit
End With
Label3.Text = px
End Sub
End Class

Related

Saving and reading files on Visual basic

Hi I'm creating a "Toilet paper tracker" on visual basic and I'm struggling with saving and reading files, I know I am missing stuff. The user should be able to login and input a threshold and when reached a warning will pop up saying "buy more toilet paper" (i haven't coded this yet) and the user can add to create a total and subtract from it too. The user should also be able to save the total to a file and I want the program to be able to read the file and change the total if the user wants to add or subtract again. It would be greatly appreciated if you pointed me in the right direction, I'm only young so it's relatively simple. Here is my program :)
Imports System.IO
Public Class frmTPT
Private Sub TPT_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call loadchangetotal()
End Sub
Sub loadchangetotal()
cboChange.Items.Add("Add to Total")
cboChange.Items.Add("Subtract from Total")
End Sub
Private Sub cboVenue_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboChange.SelectedIndexChanged
If cboChange.Text = "Add to Total" Then
Dim frmChangeACopy As New frmChangeA
frmChangeACopy.Show()
Me.Hide()
ElseIf cboChange.Text = "Subtract from Total" Then
Dim frmChangeSCopy As New frmChangeS
frmChangeSCopy.Show()
Me.Hide()
End If
End Sub
Private Sub btnReturn_Click(sender As Object, e As EventArgs)
Dim frmLoginCopy As New frmLogin
frmLoginCopy.Show()
Me.Hide()
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
txtThreshold.Text = ""
cboChange.Text = ""
txtTotal.Text = ""
End Sub
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
End
End Sub
Private Sub LogoutToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles LogoutToolStripMenuItem.Click
Dim frmLoginCopy As New frmLogin
frmLoginCopy.Show()
Me.Hide()
End Sub
Private Sub btnReadTotal_Click(sender As Object, e As EventArgs) Handles btnReadTotal.Click
Dim FileReader As StreamReader
Dim result As DialogResult
result = OpenFileDialog1.ShowDialog
If result = DialogResult.OK Then
FileReader = New StreamReader(OpenFileDialog1.Filename)
txtFileContent.Text = FileReader.ReadToEnd() 'i want to be able to read a
'previously saved total so that
FileReader.Close() 'it can be used to find the new total
'after it has been added to
End If 'or subtratced
End Sub
Private Sub SaveToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SaveToolStripMenuItem.Click
Call SaveFile()
End Sub
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Dim A, S, NewTotal As Integer
A = Val(frmChangeA.txtAdd.Text)
S = Val(frmChangeS.txtSubtract.Text)
NewTotal = A - S 'I want to be able to load a previously saved total if one exists and add and
'subtract from it
End Sub
End Class
Sub SaveFile()
Dim FileWriter As StreamWriter
Dim results As DialogResult
results = SaveFileDialog1.ShowDialog
If results = DialogResult.OK Then
FileWriter = New StreamWriter(SaveFileDialog1.FileName, False)
FileWriter.Write(txtFileContent.Text) ' is txtFileContent supposed to be
' the name of my textbox?
FileWriter.Close()
End If
End Sub
Design
You didn't mention if you were using .Net Core or 4.x. If the later, you can sometimes use the Insert Snippet functionality to learn how to do common tasks. For example in this case you could right click in the code editor and select Insert Snippet then Fundamentals then File System and finally Write text to a file. This will result in the following VB code:
My.Computer.FileSystem.WriteAllText("C:\Test.txt", "Text", True)
Unfortunately, this option doesn't work with .Net core since the My namespace wasn't ported to core.
The key point of this problem lies in reading and writing data from text. It is a clear idea to write two methods to achieve read and write.
You can refer to the following code. The two methods in the following example are WriteTotal(), ReadTotal().
Design:
Public Class Form1
Dim Oldtotal As Integer
Dim Newtotal As Integer
Private Sub btnLoadTotal_Click(sender As Object, e As EventArgs) Handles btnLoadTotal.Click
WriteTotal()
ReadTotal()
End Sub
Private Sub btnUpdateTotal_Click(sender As Object, e As EventArgs) Handles btnUpdateTotal.Click
cboChange.Text = Nothing
WriteTotal()
ReadTotal()
MsgBox("Inventory updated")
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cboChange.SelectedIndex = 0
ReadTotal()
End Sub
Sub WriteTotal()
Using swriter As IO.StreamWriter = New IO.StreamWriter("D:/paperstore.txt", False, System.Text.Encoding.UTF8)
If cboChange.Text = "Add to Total" Then
Newtotal = Oldtotal + CType(txtThreshold.Text, Integer)
swriter.WriteLine(Newtotal)
ElseIf cboChange.Text = "Subtract from Total" Then
If CType(txtThreshold.Text, Integer) > Oldtotal Then
swriter.WriteLine(Oldtotal)
MsgBox("buy more toilet paper")
Else
Newtotal = Oldtotal - CType(txtThreshold.Text, Integer)
swriter.WriteLine(Newtotal)
End If
Else
swriter.WriteLine(txtTotal.Text)
End If
End Using
End Sub
Sub ReadTotal()
Using sreader As IO.StreamReader = New IO.StreamReader("D:/paperstore.txt", System.Text.Encoding.UTF8)
Try
Oldtotal = sreader.ReadLine()
txtTotal.Text = Oldtotal
Catch ex As Exception
MsgBox(ex.Message)
End
End Try
End Using
End Sub
End Class

VB.net BackgroundWorker UI

I am trying to create an app that produces an excel document based on user input. The document can become quite extensive (multiple sheets), so I want to put the creation of the document on a BackgroundWorker and pass the progress to a ProgressBar.
I'm having problems accessing UI controls while creating the document.
How can I access multiple UI controls from a BackgroundWorker?
This is a very basic example of two of the many things that i want to do in the BackgroundWorker:
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
OpenWorkbook()
Dim Combobox() As ComboBox = {ComboBox1, ComboBox2, ComboBox3, ComboBox4}
With xlWorkBook.Sheets("Cover1")
.Range("E5").Value = TextBox1.Text
.Range("E6").Value = TextBox2.Text
.Range("E7").Value = TextBox3.Text
.Range("E8").Value = TextBox4.Text
For i = 0 To Combobox.Count - 1
.Range("A" & i + 1).Value = Combobox(i).Text
Next
End With
CloseWorkBook()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
I'm not experienced at all and after researching on this subject, I'm still not getting along with the Delegate/Invoke. Any help would be awesome. Thanks in advance.
As pointed out by Heinzi you cant just pass reference to a control into a bgw. instead you pass the values.
Option Strict On
Public Class FormControls
WithEvents Bgw As New ComponentModel.BackgroundWorker With {.WorkerReportsProgress = True}
Public Class BgwArgs
Public TxtBx1Txt As String = FormControls.TextBox1.Text
Public TxtBx2Txt As String = FormControls.TextBox2.Text
Public CmbBx1Txt As String = FormControls.ComboBox1.SelectedText
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim BgwArgs As New BgwArgs
Bgw.RunWorkerAsync(BgwArgs)
End Sub
Private Sub Bgw_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) Handles Bgw.DoWork
Dim BgwArgs As BgwArgs = DirectCast(e.Argument, BgwArgs)
.Range("E5").Value = BgwArgs.TxtBx1Txt 'etc
End Sub
End Class
I assume the OpenWorkbook is a sub that uses interop to create xlWorkBook where you would instead want to do that within the thread also, same with CloseWorkbook all that should be handled in the DoWork event and not in their own separate routines.

when the text in a textbox is equal to a certain word i need to value in the combo box to be saved for that text

I have orders in text files in the debug folder and when i type the name of the order in a text box it displays the order is a list box and there is a combo box underneath where i can change the status of the meal preparation (Being prepared, ready to deliver etc,). If i go back to that form and type in the same order name into the textbox i need to previous prepartion status to be already in the textbox. Thanks for any help!
Public Class frmOrderStatus
Private Sub btnStatus_Click(sender As Object, e As EventArgs) Handles btnStatus.Click
Dim sr As IO.StreamReader = IO.File.OpenText(strTxtOrderNum & ".txt")
Do Until sr.EndOfStream
lstOrder.Items.Add(sr.ReadLine)
Loop
End Sub
Private Sub OrderStatus_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lstOrder.Items.Clear()
btnStatus.Enabled = False
ChangeStatus.Enabled = False
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnValidate.Click
strTxtOrderNum = txtOrderNum2.Text
btnStatus.Enabled = True
ChangeStatus.Enabled = True
End Sub
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
strSaveStatus = ChangeStatus.SelectedIndex
End Sub
Private Sub ChangeStatus_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ChangeStatus.SelectedIndexChanged
End Sub
End Class
It recognizes the file; it just tells you it is in use. A Stream must be closed and disposed. I don't see the StreamReader even being closed let alone disposed. A `Using...End Using block will close and dispose of objects even if there is an error.
I just used a text file I happened to have to test.
Private strTxtOrderNum As String = "host"
Private Sub ReadFile()
Using sr As IO.StreamReader = IO.File.OpenText(strTxtOrderNum & ".txt")
Do Until sr.EndOfStream
ListBox1.Items.Add(sr.ReadLine)
Loop
End Using
End Sub
Private Sub WriteFile()
Dim strSelectedItem = ComboBox1.Text
Using swVar As IO.StreamWriter = IO.File.AppendText(strTxtOrderNum & ".txt")
swVar.WriteLine(strSelectedItem)
End Using
End Sub

Adding 150,000 records to a listview without freezing UI

I have a listview loop that is adding 150,000 items to my listview. For testing purposes I moved this code to a background worker with delegates, but it still freezes up the UI. I am trying to find a solution so that it can add these items in the background while I do other stuff in the app. What solutions do you guys recommend?
this is what I am using
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ListView1.Clear()
ListView1.BeginUpdate()
bw.WorkerReportsProgress = True
bw.RunWorkerAsync()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If bw.IsBusy Then bw.CancelAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork
For x = 1 To 125000
Dim lvi As New ListViewItem("Item " & x)
If bw.CancellationPending Then
e.Cancel = True
Exit For
Else
bw.ReportProgress(0, lvi)
End If
Next
End Sub
Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bw.ProgressChanged
Try
Dim lvi As ListViewItem = DirectCast(e.UserState, ListViewItem)
Me.ListView1.Items.Add(lvi)
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
End Sub
Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
ListView1.EndUpdate()
If Not e.Cancelled Then
Debug.Print("Done")
Else
Debug.Print("Cancelled")
End If
End Sub
End Class
Give this a try, it's a great example for what you would need... I also had a progress bar that shows the progress and such, see example image that is attached. Also I wasn't seeing any delegate that you need to perform such operation, mine has one that will be required. The reason is you are adding items to a control on the UI thread, in order to add items we need to know if an Invoke is required, if so we invoke otherwise we add the item to the control... Also I made the thread sleep, so it can take a break; this also prevents the UI from wanting to lock up here and there, now it's responsive with NO FREEZING.
Option Strict On
Option Explicit On
Public Class Form1
Delegate Sub SetListItem(ByVal lstItem As ListViewItem) 'Your delegate..
'Start the process...
Private Sub btnStartProcess_Click(sender As Object, e As EventArgs) Handles btnStartProcess.Click
lvItems.Clear()
bwList.RunWorkerAsync()
End Sub
Private Sub AddListItem(ByVal lstItem As ListViewItem)
If Me.lvItems.InvokeRequired Then 'Invoke if required...
Dim d As New SetListItem(AddressOf AddListItem) 'Your delegate...
Me.Invoke(d, New Object() {lstItem})
Else 'Otherwise, no invoke required...
Me.lvItems.Items.Add(lstItem)
End If
End Sub
Private Sub bwList_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bwList.DoWork
Dim intCount As Integer = CInt(txtCount.Text)
Dim dblPercent As Integer = 100
Dim intComplete As Integer = 0
Dim li As ListViewItem = Nothing
For i As Integer = 1 To CInt(txtCount.Text)
If Not (bwList.CancellationPending) Then
li = New ListViewItem
li.Text = "Item " & i.ToString
AddListItem(li)
Threading.Thread.Sleep(1) 'Give the thread a very..very short break...
ElseIf (bwList.CancellationPending) Then
e.Cancel = True
Exit For
End If
intComplete = CInt(CSng(i) / CSng(intCount) * 100)
If intComplete < dblPercent Then
bwList.ReportProgress(intComplete)
End If
If li IsNot Nothing Then
li = Nothing
End If
Next
End Sub
Private Sub bwList_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bwList.ProgressChanged
pbList.Value = e.ProgressPercentage
End Sub
Private Sub bwList_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bwList.RunWorkerCompleted
If pbList.Value < 100 Then pbList.Value = 100
MessageBox.Show(lvItems.Items.Count.ToString & " items were added!")
End Sub
Private Sub btnStopWork_Click(sender As Object, e As EventArgs) Handles btnStopWork.Click
bwList.CancelAsync()
End Sub
Private Sub btnRestart_Click(sender As Object, e As EventArgs) Handles btnRestart.Click
pbList.Value = 0
lvItems.Items.Clear()
txtCount.Text = String.Empty
End Sub
End Class
Screenshot in action...

VB Clicked Links Open In New Tab

I've been searching around for a while for some code to do this, and I found a couple. most of them didn't work but I'm trying to get this one to work.
Private Sub WebBrowser1_NewWindow(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles WebBrowser1.NewWindow
'This creates a new tab
Dim tp As New TabPage
TabControl1.Controls.Add(tp)
'This creates a new webbrowser with the NewWindow Event
'And navigates it to the link wanting to be opened
Dim wb As New WebBrowser
Dim myElement As HtmlElement = WebBrowser1.Document.ActiveElement
Dim target As String = myElement.GetAttribute("href")
With wb
.Navigate(target)
.Dock = DockStyle.Fill
End With
AddHandler wb.NewWindow, AddressOf WebBrowser_NewWindow
tp.Controls.Add(wb)
'This prevents ie from popping up
e.Cancel = True
End Sub
But then I get a error on here WebBrowser_NewWindow, and when I check and see what it says and I am told WebBrowser_NewWindow Is Not Declared. It may be inaccessible due to protection level How am I supposed to fix this?
Full Code
Public Class Form2
Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.BringToFront()
WebBrowser1.Navigate("www.google.com")
End Sub
Private Sub IClarityButton2_Click_1(sender As Object, e As EventArgs) Handles IClarityButton2.Click
If TextBox2.Text = "Close" Then
End
Else
TextBox2.Text = "Invalid"
End If
End Sub
Private Sub WebBrowser1_NewWindow(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles WebBrowser1.NewWindow
'This creates a new tab
Dim tp As New TabPage
TabControl1.Controls.Add(tp)
'This creates a new webbrowser with the NewWindow Event
'And navigates it to the link wanting to be opened
Dim wb As New WebBrowser
Dim myElement As HtmlElement = WebBrowser1.Document.ActiveElement
Dim target As String = myElement.GetAttribute("href")
With wb
.Navigate(target)
.Dock = DockStyle.Fill
End With
'AddHandler wb.NewWindow, AddressOf WebBrowser_NewWindow
tp.Controls.Add(wb)
'This prevents ie from popping up
e.Cancel = True
End Sub
End Class
Try removing AddHandler wb.NewWindow, AddressOf WebBrowser_NewWindow