ACHTUNG. Das ist ein Archiv des alten forum.ruby-portal.de. Die aktuelle Mailingliste gibt es auf lists.ruby-lang.org/pipermail/ruby-de.

NOTICE. This is a ready-only copy of the old forum.ruby-portal.de. You can find the current mailing list at lists.ruby-lang.org/pipermail/ruby-de.

Die Programmiersprache Ruby

Blog|

Forum|

Wiki  


Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]

Ein neues Thema erstellen Auf das Thema antworten  [ 13 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Auslesen von Daten einer Webseite.
BeitragVerfasst: 21 Jan 2017, 00:51 
Offline
Nuby

Registriert: 20 Jan 2017, 17:45
Beiträge: 6
Heyho,

ich hab mal ne Frage und zwar geht es um Folgendes. Ich will auf einer Webseite eine bestimmte Kennzahl auslesen.

Hier ist mein Code.


1
2
3
4
5
6
7
8
9
10
11
12
13
require 'nokogiri'
require 'open-uri'

url = "http://example.com/beispiel.html"

data = Nokogiri::HTML(open(url))

Kennzahlen = data.css('.KENNZAHLEN')


puts Kennzahlen.at_css('.INFOTEXT').text

puts ""


Er geht schonmal in die Richtige Klasse und findet auch die Klasse INFOTEXT. Das Problem ist nur, dass es sehr viele INFOTEXT-Klassen gibt und ich eine bestimmte brauche.

Als Beispiele:
<td class="INFOTEXT">Dividende (netto) in EUR</td>
<td class="INFOTEXT">Cashflow pro Aktie in EUR</td>

Das "Dividende (netto) in EUR" ist immer die Bezeichnung und ich habe die Hoffnung, dass man den Code oben so anpassen kann, dass er nach dem Klassennamen (INFOTEXT) und der Bezeichnung sucht.

Hoffe ihr könnt mir helfen :)

Gruß


Nach oben
 Profil  
 
BeitragVerfasst: 21 Jan 2017, 21:30 
Offline
Interpreter
Benutzeravatar

Registriert: 18 Sep 2008, 22:32
Beiträge: 1821
Wohnort: NRW → UN
Der Text „Dividende (netto) in EUR“ ist ein Textknoten (Inhalt eines Knotens), daher nicht einfach zu durchsuchen. Eine andere Möglichkeit, als alle gefundenen .INFOTEXT-Knoten zu iterieren und den Text zu prüfen, bis das gewünschte Element gefunden ist, sehe ich nicht.

Vale,
Quintus

_________________
Habe den Mut, dich deines eigenen Verstandes zu bedienen! — Immanuel Kant

Ich bin freischaffender Softwareentwickler und freue mich über jedes neue Projekt. Kontaktinformation auf meiner Website.

Mein Blog | GitHub-Profil | Auf Twitter: @qquintilianus | PGP/GPG-Schlüssel: B1FE 958E D5E8 468E AA20 8F4B F1D8 799F BCC8 BC4F


Nach oben
 Profil  
 
BeitragVerfasst: 22 Jan 2017, 14:04 
Offline
Nuby

Registriert: 20 Jan 2017, 17:45
Beiträge: 6
Danke für deine Antwort.

Quintus hat geschrieben:
Eine andere Möglichkeit, als alle gefundenen .INFOTEXT-Knoten zu iterieren und den Text zu prüfen, bis das gewünschte Element gefunden ist, sehe ich nicht.

Ich habe mich mal einer Schleife versucht, welche alle .INFOTEXT-Knoten auslesen soll so und danach den Textinhalt prüft.


Mein Problem ist nur, dass irgendetwas im Code nicht stimmt. Meine Schleife vergleicht nicht alle Möglichen .INFOTEXT - Knoten sonder lediglich den ersten.


Hier mein Code:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
require 'nokogiri'
require 'open-uri'

#die folgende URL wird untersucht.
url = "http://www.onvista.de/aktien/fundamental/Hannover-Rueck-Aktie-DE0008402215"

data = Nokogiri::HTML(open(url))

#In die Klasse KENNZAHLEN
kennzahlen = data.css('.KENNZAHLEN')

kennzahlen.each do |infotext|
#In die Klasse INFOTEXT

ke = infotext.at_css('.INFOTEXT').text
if ke.eql? "EBIT-Marge"
#Kennzahl wird ausgegeben
puts "Kennzahl: #{ke}" # "EBIT-Marge" soll ausgegeben werden
end
end

puts ""


Dazu muss man wissen, dass ich absoluter Neuling in Ruby bin :shock:

Gruß Michi


Nach oben
 Profil  
 
BeitragVerfasst: 26 Jan 2017, 11:05 
Offline
Novize

Registriert: 19 Jan 2017, 10:36
Beiträge: 19
Hallo question!

Du selektierst die .INFOTEXT elemente falsch.
Versuch's mal so:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
require 'nokogiri'
require 'open-uri'

#die folgende URL wird untersucht.
url = "http://www.onvista.de/aktien/fundamental/Hannover-Rueck-Aktie-DE0008402215"
data = Nokogiri::HTML(open(url))

# selektiere alle tablerows, die ein element mit Klasse .INFOTEXT enthalten
# und filtere sie nach text "EBIT-Marge"
# das hat den Vorteil, dass man ��ber die trs auch schnell an die Zahlen kommt...
tr = data.css("tr").select {|t| t.css(".INFOTEXT").text == "EBIT-Marge"}

# baue ein array aus den selektierten infotexten und den zugeh��rigen zahlen
ebit_daten = tr.map { |t| [t.css(".INFOTEXT").text, t.css(".ZAHL").map {|zahl| zahl.text}] }

# dieses kann man dann simpel traversieren:
ebit_daten.each do |ebit|
puts "#{ebit[0]}: #{ebit[1].join(', ')}"
end



Nach oben
 Profil  
 
BeitragVerfasst: 26 Jan 2017, 23:35 
Offline
Nuby

Registriert: 20 Jan 2017, 17:45
Beiträge: 6
Funktioniert perfekt! Danke mal schaun ob ich alles nachvollziehen kann :idea:


Nach oben
 Profil  
 
BeitragVerfasst: 27 Jan 2017, 12:51 
Offline
Novize

Registriert: 19 Jan 2017, 10:36
Beiträge: 19
Ein kleiner Tipp dazu:
seit ruby 2.4.0 gibt es die Möglichkeit, eine interaktive ruby shell (irb) aus dem Programmcode aufzurufen (require 'irb').
Versuche mal, nach zeile 14 folgendes einzufügen:


1
2
ebit_daten = tr.map { |t| [t.css(".INFOTEXT").text, t.css(".ZAHL").map {|zahl| zahl.text}] }
binding.irb



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
irb(main):002:0> tr.class
=> Array
irb(main):003:0> tr.length
=> 1
irb(main):004:0>
irb(main):005:0*
irb(main):006:0* tr.css('.INFOTEXT')
NoMethodError: undefined method `css' for #<Array:0x0055c1cc46bed0>
from (irb):6:in
`
<main>'
from question.rb:18:in `<main>
'

irb(main):007:0> tr.first('.INFOTEXT')
TypeError: no implicit conversion of String into Integer
from (irb):7:in `first'
from (irb):7:in
`
<main>'
from question.rb:18:in `<main>
'

irb(main):008:0> tr.first.css('.INFOTEXT')
=> [#<Nokogiri::XML::Element:0x2ae0e612d0bc name="td" attributes=[#<Nokogiri::XML::Attr:0x2ae0e6287e08 name="class" value="INFOTEXT">] children=[#<Nokogiri::XML::Text:0x2ae0e6287548 "EBIT-Marge">]>]
irb(main):023:0> data.css('tr').select {|t| t.css('.INFOTEXT').text == "Eigenkapitalquote"}.length
=> 1
irb(main):024:0>

Wie gesagt, das funktioniert erst ab ruby 2.4.0.
Vorher gab es diese Möglichkeit mit Pry:

gem install pry
und dann im script binding.pry

Wenn Du dann das Script aus der Console startest, hält es bei binding.irb an und startet eine interaktive Shell an der Stelle.
In dieser kann man im Scope des Scriptes sich dann den aktuellen Zustand zur Laufzeit des Scriptes ansehen (und auch ändern)!

Ich habe das exzessiv zur Erstellung meines Posts benutzt.

Sehr empfehlenswert!


Nach oben
 Profil  
 
BeitragVerfasst: 30 Jan 2017, 20:58 
Offline
Nuby

Registriert: 20 Jan 2017, 17:45
Beiträge: 6
Danke für deine Hilfe! Schau mal in PN
Gruß Michi


Nach oben
 Profil  
 
BeitragVerfasst: 31 Jan 2017, 19:51 
Offline
Nuby

Registriert: 20 Jan 2017, 17:45
Beiträge: 6
Heyho,

ich bins nochmal.. :roll:
Wie kommst du auf den Code um die Werte auszulesen? Ich versuche die ganze Zeit es zu verstehen aber es klappt irgendwie nicht. Ich will noch auf anderen Webseiten Daten auslesen und würde gerne verstehen wie ich da auf den Code komme.

z.b. hier http://www.onvista.de/news/aktien-analysen/HeidelbergCement-Analysen-DE0006047004 ich will die Analystenmeinungen rechts auslesen. Es ist ein Textknoten und damit ein anderes Objekt als die EBIT Kennzahlen.

wenn ich folgenden code starte


1
2
3
4
5
6
7
8
9
10
11
require 'nokogiri'
require 'open-uri'

#die folgende URL wird untersucht.
url = "http://www.onvista.de/news/aktien-analysen/HeidelbergCement-Analysen-DE0006047004"
data = Nokogiri::HTML(open(url))


tr = data.css("tr").select {|t| t.css(".BALKEN_CONTAINER")}

puts "#{tr}"

kommt

Zitat:
[#<Nokogiri::XML::Element:0x3fe5d4543504 name="tr" children=[#<Nokogiri::XML::Element:0x3fe5d45425c8 name="td" children=[#<Nokogiri::XML::Text:0x3fe5d45423e8 "kaufen">]>, #<Nokogiri::XML::Element:0x3fe5d4542208 name="td" children=[#<Nokogiri::XML::Element:0x3fe5d4542028 name="div" attributes=[#<Nokogiri::XML::Attr:0x3fe5d4535ddc name="class" value="BALKEN_CONTAINER">] children=[#<Nokogiri::XML::Text:0x3fe5d45351e8 " ">, #<Nokogiri::XML::Element:0x3fe5d453501c name="span" attributes=[#<Nokogiri::XML::Attr:0x3fe5d4534ec8 name="class" value="BALKEN GROSS KAUFEN">, #<Nokogiri::XML::Attr:0x3fe5d4534eb4 name="style" value="width:41%;">]>]>, #<Nokogiri::XML::Text:0x3fe5d45342fc " 19 ">]>]>,
raus was kann ich nun damit anfangen?
(Die 19 brauche ich )

Gruß Michi


Nach oben
 Profil  
 
BeitragVerfasst: 01 Feb 2017, 12:04 
Offline
Novize

Registriert: 19 Jan 2017, 10:36
Beiträge: 19
Ja die Analyse Box auf der Seite ist ganz anders aufgebaut als diese Wertetabellen im letzten Beispiel. Deshalb muss man da natürlich anders selektieren.
Am besten man schaut sich in Firefox den Quelltext an (Rechtsklick auf das Element und dann 'untersuchen'), so kann man sich die Struktur gut ansehen.

Danach (falls man es noch nicht getan hat), sollte man sich CSS-Selektoren zu Gemüte führen und verinnerlichen: https://developer.mozilla.org/de/docs/Web/CSS/CSS_Selectors

Jetzt weiss man, wie man Elemente einer Webseite selektiert und wendet dieses Wissen in seinem Programm an:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
require 'irb'
require 'nokogiri'
require 'open-uri'

def get_analysis(data)
# hier qualifiziere ich den Pfad genau, damit nur die Elemente
# selektiert werden, die ich wirklich haben will
td = data.css(".ANALYZER_TEASER.BOX > div > table > tbody > tr > td")
td.each_slice(2).map do |td|
[td[0].text.strip.to_sym, td[1].text.strip.to_i]
end.to_h
end

url = "http://www.onvista.de/news/aktien-analysen/HeidelbergCement-Analysen-DE0006047004"
data = Nokogiri::HTML(open(url))

a = get_analysis(data)
p a

binding.irb


Experimentier an der Stelle mal ein wenig mit Selektionen und deren Verarbeitung herum und teil' uns das Ergebnis mit :)

P.S.: Firefox (andre Browser auch) haben mächtige Javascript-Konsolen, in denen man die Webseiten
auslesen und manipulieren kann. Lade also mal Deine Seite und drück F12 und dann unten console.

tr = document.querySelectorAll(".ANALYZER_TEASER.BOX tr td")
-> NodeList [ <td>, <td>, <td>, <td>, <td>, <td> ]

Die Nokigiri-Methode css ist also ein Klon von document.querySelectorAll (naja wahrscheinlich kann css noch mehr, aber da müsste man sich mal die Dokumentation anschauen).


Nach oben
 Profil  
 
BeitragVerfasst: 04 Feb 2017, 21:07 
Offline
Nuby

Registriert: 20 Jan 2017, 17:45
Beiträge: 6
Danke für deine Antwort!

Die Seite https://developer.mozilla.org/de/docs/Web/CSS/CSS_Selectors ist echt gut. Ich denk damit sollte ich in Zukunft gut arbeiten können. :)

Den Code von dir habe ich ein bisschen umgeändert und die Daten in einem Array gespeichert statt des Hashes, da ich mit Arrays einfach mehr Erfahrung habe.

Mit dem binding.irb habe ich auch mal ein bisschen rumgespielt aber eine wirkliche Erkenntnis bot mir das Tool nicht. Vielleicht liegt es auch daran, dass ich einfach keine Erfahrungen habe was CSS / HTML und Shellkommandos angeht.

Auf jedenfall Vielen Dank!!


Nach oben
 Profil  
 
BeitragVerfasst: 12 Feb 2017, 00:15 
Offline
Novize

Registriert: 19 Jan 2017, 10:36
Beiträge: 19
Hashes und Arrays sind in ruby quasi austauschbar:



1
2
3
4
5
6
irb(main):005:0> hash = { :x => 'b', :y => 'c'}
=> {:x=>"b", :y=>"c"}
irb(main):006:0> arr = hash.to_a
=> [[:x, "b"], [:y, "c"]]
irb(main):007:0> arr.to_h
=> {:x=>"b", :y=>"c"}


wenn ich mich nicht recht irre, sind sogar die Werte, die in einem Hash gespeichert werden, ab Version 2.4 der Reihenfolge nach statisch, wie in einem Array, (was man in jedem Informatikstudium anders beigebracht bekommt).

sprich :



1
2
3
4
irb(main):008:0> x = { :a => 'oink', :b => 'bingo' }
=> {:a=>"oink", :b=>"bingo"}
irb(main):009:0> x.to_a[0]
=> [:a, "oink"]


x.to_a[0] ist in ruby mittlerweile GARANTIERT [:a, "oink"] (weil der Hash in der Reihenfolge erstellt wurde).
Ich finde das genial: Arrays lassen sich einfach in Hashes und umgekehrt Transformieren, ohne die Reihenfolge der Elemente zu missachten.

Folgendes Beispiel:



1
2
3
4
5
6
7
8
9
10
11
irb(main):018:0> a = {}
=> {}
irb(main):019:0> 17.times {|t| a[t] = rand(200) }
=> 17
irb(main):020:0> a
=> {0=>188, 1=>192, 2=>64, 3=>191, 4=>49, 5=>24, 6=>132, 7=>9, 8=>48, 9=>85, 10=>135, 11=>160, 12=>154, 13=>17, 14=>145, 15=>55, 16=>89}
irb(main):027:0> a.to_a
=> [[0, 188], [1, 192], [2, 64], [3, 191], [4, 49], [5, 24], [6, 132], [7, 9], [8, 48], [9, 85], [10, 135], [11, 160], [12, 154], [13, 17], [14, 145], [15, 55], [16, 89]]
irb(main):026:0> a.to_h.to_a
=> [[0, 188], [1, 192], [2, 64], [3, 191], [4, 49], [5, 24], [6, 132], [7, 9], [8, 48], [9, 85], [10, 135], [11, 160], [12, 154], [13, 17], [14, 145], [15, 55], [16, 89]]


Die Reihenfolge wird beibehalten!
Da ich mich eh ein bischen verritten hab, überlasse ich den Beweis Anderen :D


Nach oben
 Profil  
 
BeitragVerfasst: 12 Feb 2017, 22:55 
Offline
Interpreter
Benutzeravatar

Registriert: 18 Sep 2008, 22:32
Beiträge: 1821
Wohnort: NRW → UN
bazziboy hat geschrieben:
wenn ich mich nicht recht irre, sind sogar die Werte, die in einem Hash gespeichert werden, ab Version 2.4 der Reihenfolge nach statisch, wie in einem Array, (was man in jedem Informatikstudium anders beigebracht bekommt).


Die Ordered Hashes sind schon sehr viel länger dabei. Die wurden irgendwo in der 1.9er-Serie eingeführt. Ich war auf die Schnelle nicht in der Lage, das im Changelog zu finden, aber es gibt Einträge von 2007, die Bezug darauf nehmen. Ich persönlich verlasse mich nicht gern auf die Ordnung von Hashes, und wenn ich es tue, dann kommt da ein Kommentar dran, weil die Sache mit den Ordered Hashes nicht jedermann bekannt ist. Eben weil es in sehr vielen anderen Programmiersprachen anders ist.

Vale,
Quintus

_________________
Habe den Mut, dich deines eigenen Verstandes zu bedienen! — Immanuel Kant

Ich bin freischaffender Softwareentwickler und freue mich über jedes neue Projekt. Kontaktinformation auf meiner Website.

Mein Blog | GitHub-Profil | Auf Twitter: @qquintilianus | PGP/GPG-Schlüssel: B1FE 958E D5E8 468E AA20 8F4B F1D8 799F BCC8 BC4F


Nach oben
 Profil  
 
BeitragVerfasst: 17 Feb 2017, 11:38 
Offline
Novize

Registriert: 19 Jan 2017, 10:36
Beiträge: 19
Ich bezog mich dabei auf folgenden Post: https://bugs.ruby-lang.org/issues/12142
Zitat:
removing doubly linked lists and putting the elements into an array
for accessing to elements by their inclusion order. That also
removes pointer chaising on the doubly linked lists used for
traversing elements by their inclusion order.

Deshalb ging ich davon aus, daß das Feature erst seit 2.4.0 existiert.


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 13 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach: