Werte aus einer Webseite auslesen

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von DusMil.

    Werte aus einer Webseite auslesen

    Edit by ErfinderDesRades: (Thema verschoben) Bitte richtiges UnterForum wählen!

    Hallo zusammen

    Bin neu hier, darum kenne ich mich hier nicht so gut aus! :S Ich hoffe dennoch, dass ihr mir helfen könnt.


    Ich möchte von einer Webseite (nbs.rs/export/sites/default/in…sh/scripts/kl_devize.html) die aktuellen Kurse auslesen, aber das Problem ist, dass es keine ID sondern nur eine class hat. Jetzt weiss ich nicht wie ich vorgehen soll, denn die Zahl kommt in ein Label.


    Wäre sehr toll, wenn ihr mir helfen könntet! :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hi @DusMil:
    Vielleicht mal eine kleine Erklärung.
    Zuerst schaust du dir die Website an und untersuchst den Quelltext.
    Auffällig ist, dass die Daten so nicht im reinen Quelltext stehen. Bei genauem Hingucken erkennt man aber, dass offenbar ein iFrame geladen wird.
    Das hätte man auch über die Console (z.B in chrome) herausfinden können.



    Als Link erhalten wir das hier. nbs.rs/kursnaListaModul/zaDevize.faces?lang=eng
    Rufen wir nun diese Seite auf, finden wir unsere Tabelle.
    Nun brauchen wir den Quelltext dieser Seite.
    Da würde ich entweder WebClient.DownloadString() oder HttpWebRequest benutzen.
    (Die jeweiligen Async-Methoden sind schöner)

    Herauskommen würde folgendes.

    VB.NET-Quellcode

    1. 'Request erstellen
    2. Dim request As HttpWebRequest = _
    3. CType(WebRequest.Create("http://www.nbs.rs/kursnaListaModul/zaDevize.faces?lang=eng"), HttpWebRequest)
    4. Dim response As WebResponse = request.GetResponse()
    5. Dim dataStream As Stream = response.GetResponseStream()
    6. Dim reader As New StreamReader(dataStream)
    7. Dim responseFromServer As String = reader.ReadToEnd()
    8. reader.Close()
    9. response.Close()

    Nun hast du den Quelltext. Für das Auswerten könnte man RegularExpressions verwenden, aber probier' das mal selbst.
    Vielen, vielen Dank, für deine Erklärung, sie ist sehr ausführlich und hilfreich!!!


    Beim ausprobieren, hab ich die Seite (nur Tabelle) auch gefunden, aber ich wusste nicht, wie ich das jetzt in die Labels bekomme.

    Bitte hilf mir weiter, denn ich kenne nur das mit "Documents.GetbyID", alles andere kenne ich leider nicht! Ich möchte es aber gerne lernen.

    Wie bekomme ich eine Zahl in ein Label und eine andere Zahl in ein anderes Label?
    @DusMil:
    Abend. Sowas könnte man wie gesagt mit RegEx machen. [Allgemein] Regular Expressions von 0 an
    Allerdings ist das für deinen Fall recht schwer zu behandeln.
    Da würde ich etwas fertiges benutzen.
    Das hier sieht gut aus. (Quelle: nullskull.com/q/10295083/read-…tml-file-to-dataset-.aspx)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Function ConvertHTMLTablesToDataSet(ByVal HTML As String) As DataSet
    2. ' Declarations
    3. Dim ds As New DataSet
    4. Dim dt As DataTable
    5. Dim dr As DataRow
    6. Dim TableExpression As String = "<table[^>]*>(.*?)</table>"
    7. Dim HeaderExpression As String = "<th[^>]*>(.*?)</th>"
    8. Dim RowExpression As String = "<tr[^>]*>(.*?)</tr>"
    9. Dim ColumnExpression As String = "<td[^>]*>(.*?)</td>"
    10. Dim HeadersExist As Boolean = False
    11. Dim iCurrentColumn As Integer = 0
    12. Dim iCurrentRow As Integer = 0
    13. ' Get a match for all the tables in the HTML
    14. Dim Tables As MatchCollection = Regex.Matches(HTML, TableExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase)
    15. ' Loop through each table element
    16. For Each Table As Match In Tables
    17. ' Reset the current row counter and the header flag
    18. iCurrentRow = 0
    19. HeadersExist = False
    20. ' Add a new table to the DataSet
    21. dt = New DataTable
    22. ' Create the relevant amount of columns for this table (use the headers if they exist, otherwise use default names)
    23. If Table.Value.Contains("<th") Then
    24. ' Set the HeadersExist flag
    25. HeadersExist = True
    26. ' Get a match for all the rows in the table
    27. Dim Headers As MatchCollection = Regex.Matches(Table.Value, HeaderExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase)
    28. ' Loop through each header element
    29. For Each Header As Match In Headers
    30. dt.Columns.Add(Header.Groups(1).ToString)
    31. Next
    32. Else
    33. For iColumns As Integer = 1 To Regex.Matches(Regex.Matches(Regex.Matches(Table.Value, TableExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase).Item(0).ToString, RowExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase).Item(0).ToString, ColumnExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase).Count
    34. dt.Columns.Add("Column " & iColumns)
    35. Next
    36. End If
    37. ' Get a match for all the rows in the table
    38. Dim Rows As MatchCollection = Regex.Matches(Table.Value, RowExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase)
    39. ' Loop through each row element
    40. For Each Row As Match In Rows
    41. ' Only loop through the row if it isn't a header row
    42. If Not (iCurrentRow = 0 And HeadersExist = True) Then
    43. ' Create a new row and reset the current column counter
    44. dr = dt.NewRow
    45. iCurrentColumn = 0
    46. ' Get a match for all the columns in the row
    47. Dim Columns As MatchCollection = Regex.Matches(Row.Value, ColumnExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase)
    48. ' Loop through each column element
    49. For Each Column As Match In Columns
    50. ' Add the value to the DataRow
    51. dr(iCurrentColumn) = Column.Groups(1).ToString
    52. ' Increase the current column
    53. iCurrentColumn += 1
    54. Next
    55. ' Add the DataRow to the DataTable
    56. dt.Rows.Add(dr)
    57. End If
    58. ' Increase the current row counter
    59. iCurrentRow += 1
    60. Next
    61. ' Add the DataTable to the DataSet
    62. ds.Tables.Add(dt)
    63. Next
    64. Return (ds)
    65. End Function


    Aurufen würde man das so.

    VB.NET-Quellcode

    1. ...
    2. Dim s As DataSet = Me.ConvertHTMLTablesToDataSet(responseFromServer)
    3. DataGridView1.DataSource = s.Tables(1)

    Dann hätte man die Daten in einer Tabelle und kann sie von da besser bearbeiten.
    Welche Daten willst du denn genau in einem Label darstellen?
    Bilder
    • vbtest.png

      48,61 kB, 940×520, 284 mal angesehen
    Vielen Dank für deine Hilfe!!!


    Ich weiss jetzt leider nicht, wo ich deinen Code einfügen soll?


    Und zu deiner Frage: Es gibt pro Währung immer zwei Labels (EUR1(Verkaufskurs) und EUR2(Ankaufskurs)) im EUR1 soll die Zahl aus der zweitletzten Spalte stehen (also 115.7769 ) und in EUR2 die Zahl aus der letzten Spalte (also 116.4737 ). Ich brauche nicht alle Währungen sondern nur EUR (EUR1 und EUR2), CHF (CHF1 und CHF2), USD (USD1 und USD2).
    Den Code den ich dir vorgelegt habe, ist eine Methode (besser gesagt Function, da sie einen Rückgabewert hat).
    Diese kopierst du einfach und fügst sie in deinen Code ein.
    Struktur

    VB.NET-Quellcode

    1. Public Sub WasWeissIch()
    2. '...
    3. End Sub
    4. Public Sub ....

    Das Schlüsselwort Sub leitet eine Methode (oder Function) ein.
    Den Aufruf musst du dann machen, wann du ihn haben willst. (Buttonklick, Formload ...)
    Ich würde ihn im FormLoad machen. (D.h. den Aufrufcode, den ich dir gezeigt habe in's FormLoad schreiben)

    In deiner DataTable stehen ja jetzt deine gewünschten Werte. Also kannst du diese auch ganz bequem herausnehmen.
    Euro steht in der ersten Reihe, also holst du dir diese.
    Die Werte die du haben möchtest stehen jeweils in der vierten und fünften Spalte. Also musst du dir diese auch holen.

    VB.NET-Quellcode

    1. '...
    2. 'In der zweiten Tabelle stehen deine Wert
    3. DataGridView1.DataSource = s.Tables(1)
    4. 'Erste Spalte ist Euro
    5. Dim row As DataRow = s.Tables(1).Rows(0)
    6. 'In Spalte 4 und 5 stehen deine Raten
    7. 'Erste Rate holen
    8. Dim one As String = row.Item(4).ToString()
    9. 'Zweite holen
    10. Dim two As String = row.Item(5).ToString()


    Nun bist du mit dieser Aufgabe fertig, aber hast selber fast nichts programmiert. Wichtig ist, dass du dir ein Buch o.ä. zulegst, denn sonst wird es schwer
    eine Programmiersprache zu lernen.
    Wenn du hier Fragen stellst und bei den Antworten etwas nicht verstehst, immer nachfragen! Die Eigeninitiative soll aber nicht zu kurz kommen.

    Grüße.
    Bilder
    • kurse.png

      1,2 kB, 301×89, 216 mal angesehen
    Geh mal mit der Maus über den Fehler und öffne dann dieses kleine Fenster.
    Da wird dir vorgeschlagen "System.Text.RegularExpressions importieren" klick da mal drauf.
    (Oder ganze oben im Code Imports System.Text.RegularExpressions schreiben)
    Grund ist, dass Dinge die man nicht immer beim Programmieren benutzt ausgelagert sind, sodass man sie explizit verweisen muss.

    Zeig mal deinen bisherigen Code bitte.
    Der Fehler sagt dir, dass "responseFromServer" nicht existiert. Du musst die Variable wie oben beschrieben erzeugen.
    "Match" habe ich importiert, jetzt geht es, aber das mit dem "responseFromServer" kann ich immer noch nicht lösen.


    Das ist mein bisheriger Code:


    VB.NET-Quellcode

    1. Imports System.Text.RegularExpressions
    2. Public Class Form1
    3. Private Function ConvertHTMLTablesToDataSet(ByVal HTML As String) As DataSet ' Declarations Dim ds As New DataSet Dim dt As DataTable Dim dr As DataRow
    4. Dim TableExpression As String = "<table[^>]*>(.*?)</table>" Dim HeaderExpression As String = "<th[^>]*>(.*?)</th>" Dim RowExpression As String = "<tr[^>]*>(.*?)</tr>" Dim ColumnExpression As String = "<td[^>]*>(.*?)</td>" Dim HeadersExist As Boolean = False Dim iCurrentColumn As Integer = 0 Dim iCurrentRow As Integer = 0
    5. ' Get a match for all the tables in the HTML Dim Tables As MatchCollection = Regex.Matches(HTML, TableExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase) ' Loop through each table element For Each Table As Match In Tables ' Reset the current row counter and the header flag iCurrentRow = 0 HeadersExist = False ' Add a new table to the DataSet dt = New DataTable ' Create the relevant amount of columns for this table (use the headers if they exist, otherwise use default names) If Table.Value.Contains("<th") Then ' Set the HeadersExist flag HeadersExist = True ' Get a match for all the rows in the table Dim Headers As MatchCollection = Regex.Matches(Table.Value, HeaderExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase) ' Loop through each header element For Each Header As Match In Headers dt.Columns.Add(Header.Groups(1).ToString) Next Else For iColumns As Integer = 1 To Regex.Matches(Regex.Matches(Regex.Matches(Table.Value, TableExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase).Item(0).ToString, RowExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase).Item(0).ToString, ColumnExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase).Count dt.Columns.Add("Column " & iColumns) Next End If ' Get a match for all the rows in the table Dim Rows As MatchCollection = Regex.Matches(Table.Value, RowExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase) ' Loop through each row element For Each Row As Match In Rows ' Only loop through the row if it isn't a header row If Not (iCurrentRow = 0 And HeadersExist = True) Then ' Create a new row and reset the current column counter dr = dt.NewRow iCurrentColumn = 0 ' Get a match for all the columns in the row Dim Columns As MatchCollection = Regex.Matches(Row.Value, ColumnExpression, RegexOptions.Multiline Or RegexOptions.Singleline Or RegexOptions.IgnoreCase) ' Loop through each column element For Each Column As Match In Columns ' Add the value to the DataRow dr(iCurrentColumn) = Column.Groups(1).ToString ' Increase the current column iCurrentColumn += 1 Next ' Add the DataRow to the DataTable dt.Rows.Add(dr) End If ' Increase the current row counter iCurrentRow += 1 Next ' Add the DataTable to the DataSet ds.Tables.Add(dt) Next Return (ds) End Function
    6. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    7. Dim s As DataSet = Me.ConvertHTMLTablesToDataSet(responseFromServer)
    8. DataGridView1.DataSource = s.Tables(1) 'Erste Spalte ist Euro Dim row As DataRow = s.Tables(1).Rows(0) 'In Spalte 4 und 5 stehen deine Raten 'Erste Rate holen Dim one As String = row.Item(4).ToString() 'Zweite holen Dim two As String = row.Item(5).ToString()
    9. EUR1.Text = one EUR2.Text = two
    10. End SubEnd Class
    Formatier' mal deinen Code richtig, sonst kann man ihn leider nicht lesen. [01 Forum] Bitte VB-Tag(s) benutzen - was ist damit gemeint? Oder: Wie füge ich Quellcode korrekt im Forum ein?
    Ich habe den Fehler aber schon gefunden. Das hier steht in deinem Code.

    VB.NET-Quellcode

    1. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    2. Dim s As DataSet = Me.ConvertHTMLTablesToDataSet(responseFromServer)
    3. '...
    4. End Sub

    Aber woher kommt denn responseFromServer? Du übergibst es an die Funktion, aber es existiert gar nicht.
    Das ist ein String, wo der Quelltext drinsteht. Du gibst ihn an die Funktion und die liefert dir eine Tabelle (genauer DataSet) mit deinen Infos.
    Also musst du den Quelltext erstmal wie in meinem ersten Post beschrieben, runterladen.
    Die Methode wie man das macht steht da. Diese musst du ins FormLoad vor deinen jetzigen Code schreiben. :)