Mit curl und POST fremde Webseiten auslesen

Sinalco

Grünschnabel
Hallo zusammen,

ich versuche zur Zeit mit einem PHP-Skript die Preise eines Stromanbieters selbst auszulesen.
Manch einer wird jetzt denken, warum schaust du nicht auf den bekannten Vergleichsportalen nach?
Da gibt es mehrere Gründe, einer ist zum Beispiel das ich einfach mal versuchen möchte mir ein eigens Skript aufzubauen und ich gemerkt habe das die bekannten Vergleichsportale nicht immer den günstigsten Preis anzeigen.

Bei den meisten Anbietern muss die PLZ und der Verbau in KWh in einem HTML Formular Eingetragen werden und erst dann kann die Website ausgelesen werden kann.
Mein Problem ist jetzt, das ich das Formular ausfüllen kann aber ich bekomme nicht die Preise zurück sondern nur die Website mit den eingegeben Daten wie PLZ und kWh sowie das es sich um private Haushalte handelt:

Hier läuft das Skipt aktuell zum testen:
Testserver

So sieht das Skript aus:

PHP:
<?php
//create array of data to be posted
$post_data['tariff[zipcode]'] = '10551';
$post_data['tariff[consumption]'] = '2000';
$post_data['tariff[is_strom]'] = 'true';
$post_data['tariff[country]'] = '';
$post_data['sendCalc'] = '';
$post_data['tariff[is_privat]'] = 'true';

//traverse array and prepare data for posting (key1=value1)
foreach ( $post_data as $key => $value) {
    $post_items[] = $key . '=' . $value;
}

//create the final string to be posted using implode()
$post_string = implode ('&', $post_items);

//create cURL connection
$curl_connection =
  curl_init('https://immergruen-energie.de/tarife');

//set options
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
curl_setopt($curl, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($curl, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_POST, true);

//set data to be posted
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $post_string);

//perform our request
$result = curl_exec($curl_connection);
print $result;

//close the connection
curl_close($curl_connection);
?>

Was muss ich machen um die Preise angezeigt zu bekommen?
 

ComFreek

Mod | @comfreek
Moderator
Die benötigten Werte aus der Ausgabe in $result extrahieren. Je nach Art, wie die Werte in der Ausgabe vorliegen, kann man manuelle Methoden (String-Funktionen wie strpos, ... und RegEx) oder HTML-Parser einsetzen. Das "oder" ist nicht exklusiv, man kann auch zuerst alles als HTML parsen und dann nur einzelne Inhalte via RegEx aufbereiten.

Als ersten Schritt solltest du dir anschauen, wie die Daten, die du möchtest, im HTML vorliegen.
 

Sinalco

Grünschnabel
Die benötigten Werte aus der Ausgabe in $result extrahieren. Je nach Art, wie die Werte in der Ausgabe vorliegen, kann man manuelle Methoden (String-Funktionen wie strpos, ... und RegEx) oder HTML-Parser einsetzen. Das "oder" ist nicht exklusiv, man kann auch zuerst alles als HTML parsen und dann nur einzelne Inhalte via RegEx aufbereiten.

Als ersten Schritt solltest du dir anschauen, wie die Daten, die du möchtest, im HTML vorliegen.

Hi ComFreek,
das ist nicht das Problem, die Werte aus der HTML zu parsen.
Ich bekomme die Werte mit curl erst gar nicht angezeigt.

Das ist die Orginalseite manuell im Browser ausgefüllt Willkommen | immergrün!:
1.PNG

Das ist mein Skript mit curl über den Testserver aufgerufen:
2.PNG

Hier fehlen die Preise somit kann ich auch nicht danach parsen.
 

ComFreek

Mod | @comfreek
Moderator
Dann sendest du nicht denselben Request wie dein Browser. Untersuche den HTTP Request von deinem Browser mit DevTools und stelle ihn nach.
 

Sinalco

Grünschnabel
Das ist genau mein Problem, dass ich mich nicht so auskenne mit den HTTP Request, den Cookies usw.
Das DevTool von Chrome verwende ich bereits.
Meine Vermutung ist, dass es nicht funktioniert, weil ich den tariff[_token] nicht mitsende.

Das sind die Formular Daten die Abgeschickt werden wenn, man auf der orginal Seite das Formular ausfüllt:
3.PNG

Kann mir jemand wie man so ein Token mit PHP generieren kann?
 

ComFreek

Mod | @comfreek
Moderator
Das sieht ganz nach einem Anti-CSRF-Token aus. Du müsstest also zuerst die Website, die das Formular zeigt, via curl dir laden. Aus dem HTML daraus das Token extrahieren und dann den curl-Request absenden, den du gerade absendest - mit dem Token zusätzlich als POST Field.

Ich würde auch dasselbe Cookie-File nutzen bei beiden Requests.


Hintergrund: Du kannst das Token nicht selbst generieren. Der Punkt bei Anti-CSRF-Tokens ist gerade, dass der Server die zufällig beim Besuchen der Formularseite generiert.
 

Bratkartoffel

gebratene Kartoffel
Premium-User
Hi,

mal so nebenbei gefragt: Hast du mal nachgefragt ob du die Seiten /den Dienst verwenden darfst? Wenn ich deine Seite aufrufe, dann sieht die vom Look&Feel her täuschend ähnlich aus (Phishing)
Kurz: Hast du die Erlaubnis von "immer grün", dass du deren Seite / Dienst so verwenden darfst? Eventuell bieten die auch eine REST-API (o.ä.) für sowas an.

Grüsse,
BK
 

Sinalco

Grünschnabel
Ok also generiert wird der Token auch mit meinem Skript, wenn ich nach dem Laden noch manuell im Browser auf "Tarif anpassen" und dann auf "Berechnen" klicke.
Das versuch ich mal zu automatisieren.

Die Preise werden aber trotzdem nicht angezeigt.
Allerdings sind die Cookies nicht so wie auf der Original-Seite.
Gibt es da noch eine Möglichkeit diese anzupassen, momentan verwende ich nur:
PHP:
curl_setopt($curl, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($curl, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');

Oder bin ich da auf dem Holzweg.

@Bratkartoffel:
Ich habe nicht vor die Seite zu kopieren, die sieht natürlich gleich aus wie die Originale weil ich sie per PHP aufrufe und dann ausgebe, ist nur zum testen so. Mich interessieren nur die Preise, die ich dann rausfiltern kann, rechtlich muss das natürlich noch abgeklärt werden wenn ich das öffentlich mache. Momentan möchte ich einfach die Machbarkeit testen.