Inhalte Parsen von Website

koche82

Mitglied
Hallo Community,

ich benötige beim Parsen von Inhalten einer Website eure Hilfe. Genauer gesagt geht es um das Parsen von Options-Werten des Werte Coca Cola auf der Seite nasdaq.com. Beim Aufruf der Seite https://api.nasdaq.com/api/quote/KO...xcode=oprac&callput=callput&money=at&type=all über den Browser erhalte ich informationen (als json) über das Wertpapier gemäß den gesetzten Parametern.

Wenn ich nun versuche, die Website mittels HttpURLConnection oder unirest zu parsen, geht meine Anfrage immer in einen Timeout.

Mein Sourcecode:
Java:
HttpResponse<JsonNode> response = Unirest.get("https://api.nasdaq" +
                    ".com/api/quote/KO/option-chain?assetclass=stocks&limit=60&fromdate=2023-02-17&todate=2023-02-17" +
                    "&excode=oprac&callput=callput&money=at&type=all")
                    .header("accept", "application/json")
                    .asJson();

bzw.

Java:
URL obj = new URL("https://api.nasdaq" +
                    ".com/api/quote/KO/option-chain?assetclass=stocks&limit=60&fromdate=2023-02-17&todate=2023-02-17" +
                    "&excode=oprac&callput=callput&money=at&type=all");
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();


Beim Aufruf via curl erhalte ich die folgende Nachricht:

HTML:
<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD><BODY>
<H1>Access Denied</H1>
 
You don't have permission to access "http&#58;&#47;&#47;api&#46;nasdaq&#46;com&#47;api&#47;quote&#47;KO&#47;option&#45;chain&#63;" on this server.<P>
Reference&#32;&#35;18&#46;87a12417&#46;1671046560&#46;95b4f343
</BODY>
</HTML>


Wirklich nachvollziehen, warum ich keine Berechtigung habe, kann ich leider nicht. Immerhin ist für die Abfrage keine Anmeldung erforderlich und in den Request Headers ist auch nicht nachvollziehbar, dass hier irgendwelche Cookies gesetzt sind.

Anbei die Header, die bei der Anfrage gesetzt sind (diese habe ich ebenfalls schon übernommen, trotzdem hat sich am Verhalten nichts geändert)
Code:
:authority: api.nasdaq.com
:method: GET
:path: /api/quote/KO/option-chain?assetclass=stocks&limit=60&fromdate=2023-02-17&todate=2023-02-17&excode=oprac&callput=callput&money=at&type=all
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
sec-ch-ua: "Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: none
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36


Habt ihr eine Idee, was hier schief läuft bzw. sich die Anfrage über Unirest/HttpURLConnection gegenüber der Abfrage über den Browser unterscheidet?
 
Ich habe die URL gerade mal in einer alten App von mir ausprobiert, wo ich auch mit einer URLConnection arbeite. Bei mir geht der Inhalt der Seite ganz normal auf, genauso wie im Browser.

Ich glaube aber auch, dass, wenn dein Code auch die Access Denied Antwort bekommen würde, kein Timeout auftreten würde, sondern eine andere Exception. Was genau machst du denn nach dem Aufruf von obj.openConnection()?
 
Und neben dem Problem mit der Verbindung: Du hast da keine Webseite zu parsen. Webseite wäre HTML. Was Du da hast ist ein REST Service und Du bekommst JSON zurück.

Da ist es das Einfachste, wenn Du die Datenstruktur erstellst und dann einfach das JSON in deine Datenstruktur umwandeln lässt (Das wäre ein unmarshal wenn Du nach dem Namen der Operation suchen willst). Und Libraries dafür gibt es viele ... Jackson und GSON sind wohl die verbreitesten.

Und ggf. ist es einfacher, da einfach ein entsprechendes fertiges SDk zu nutzen ... eine Suche hat mir z.B. direkt https://github.com/Nasdaq/NasdaqCloudDataService-SDK-Java gegeben. Die deckt das ggf. schon ab.

Die Links mögen evtl. eine falsche API von nasdaq betreffen, aber generell sollte es auch zu der API, die Du da nutzen willst, fertige Lösungen geben.
 
Ich habe die URL gerade mal in einer alten App von mir ausprobiert, wo ich auch mit einer URLConnection arbeite. Bei mir geht der Inhalt der Seite ganz normal auf, genauso wie im Browser.
Kannst du mir mal den Quellcode zeigen, damit ich sehen kann, wie sich der gegenüber meinem unterscheidet?

Was genau machst du denn nach dem Aufruf von obj.openConnection()?
Egal, ob ich hier versuche den InputStream zu lesen oder den ResponseCode zu holen, ich lande immer im Nirvana. Mein Programm reagiert dann nicht mehr.
 
Und neben dem Problem mit der Verbindung: Du hast da keine Webseite zu parsen. Webseite wäre HTML. Was Du da hast ist ein REST Service und Du bekommst JSON zurück.
Korrekt, das habe ich falsch formuliert. Deswegen habe ich zuerst auch Unirest verwendet, um damit das JSON-Objekt abzuholen. Leider hatte ich damit auch keinen Erfolg.
Und ggf. ist es einfacher, da einfach ein entsprechendes fertiges SDk zu nutzen ... eine Suche hat mir z.B. direkt https://github.com/Nasdaq/NasdaqCloudDataService-SDK-Java gegeben. Die deckt das ggf. schon ab.

Die Links mögen evtl. eine falsche API von nasdaq betreffen, aber generell sollte es auch zu der API, die Du da nutzen willst, fertige Lösungen geben.
Klingt interessant für die Zukunft, für meinen derzeitigen Anwendungsfall halte ich es aber für "oversized" und anhand der Doku kann ich nicht erkennen, ob ich die Daten abholen kann, die ich benötige. Vereinzelte Werte sind für mich vollkommend ausreichend.
 
Kopier doch mal den Request aus dem Browser als cURL-Request und probiers damit mal. Das muss eigentlich funktionieren.
Leider nicht. Die Header habe ich in eine eigene Datei ausgelagert und curl mit dem folgenden Befehl ausgeführt

Code:
curl -H @headers.txt https://api.nasdaq.com/api/quote/KO/option-chain?assetclass=stocks

Damit habe ich die Access Denied Antwort bekommen, die ich oben gepostet habe
 
Leider nicht. Die Header habe ich in eine eigene Datei ausgelagert und curl mit dem folgenden Befehl ausgeführt
Habe es gerade probiert: funktioniert einwandfrei.

Mal im Detail, z. B. mit Firefox, Link öffnen (JSON wird angezeigt), F12 -> Netzwerkanalyse -> Seite neu laden. Rechtsklick auf den Request -> Wert kopieren -> als cURL-Adresse kopieren (POSIX). In Shell einfügen (unter Windows ggf. WSL verwenden), ausführen und curl empfängt binäre Daten. An die curl-Optionen noch ein --compressed anfügen und es wird das JSON-Dokument angezeigt.

Noch die Cookie- und Referrer-Header entfernt, funktioniert immer noch:
Code:
curl 'https://api.nasdaq.com/api/quote/KO/option-chain?assetclass=stocks&limit=60&fromdate=2023-02-17&todate=2023-02-17&excode=oprac&callput=callput&money=at&type=all' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' -H 'Accept-Language: de,en-US;q=0.7,en;q=0.3' -H 'Accept-Encoding: gzip, deflate, br'  -H 'Connection: keep-alive'  -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: cross-site' --compressed
 
Kannst du mir mal den Quellcode zeigen, damit ich sehen kann, wie sich der gegenüber meinem unterscheidet?
Genau dafür hatte ich ja gefragt, was du danach machst. 😂

Also falls es dir weiterhilft, mein Code sieht ungefähr so aus:
Java:
URL url = new URL(urlString);
URLConnection urlConnection = url.openConnection();
urlConnection.setConnectTimeout(timeout);
if (forceDesktop)
    urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4");
urlConnection.connect();
InputStream content = (InputStream) urlConnection.getContent();
 
Habe es gerade probiert: funktioniert einwandfrei.

Mal im Detail, z. B. mit Firefox, Link öffnen (JSON wird angezeigt), F12 -> Netzwerkanalyse -> Seite neu laden. Rechtsklick auf den Request -> Wert kopieren -> als cURL-Adresse kopieren (POSIX). In Shell einfügen (unter Windows ggf. WSL verwenden), ausführen und curl empfängt binäre Daten. An die curl-Optionen noch ein --compressed anfügen und es wird das JSON-Dokument angezeigt.

Noch die Cookie- und Referrer-Header entfernt, funktioniert immer noch:
Code:
curl 'https://api.nasdaq.com/api/quote/KO/option-chain?assetclass=stocks&limit=60&fromdate=2023-02-17&todate=2023-02-17&excode=oprac&callput=callput&money=at&type=all' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' -H 'Accept-Language: de,en-US;q=0.7,en;q=0.3' -H 'Accept-Encoding: gzip, deflate, br'  -H 'Connection: keep-alive'  -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: cross-site' --compressed

💪 mit der cURL Anfrage bekomme ich die Daten auch übermittelt. Dann gehe ich mal die einzelnen Header durch. Vielleicht habe ich einen vergessen.

Vielen herzlichen Dank 👍
 
Genau dafür hatte ich ja gefragt, was du danach machst. 😂

Also falls es dir weiterhilft, mein Code sieht ungefähr so aus:
Java:
URL url = new URL(urlString);
URLConnection urlConnection = url.openConnection();
urlConnection.setConnectTimeout(timeout);
if (forceDesktop)
    urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4");
urlConnection.connect();
InputStream content = (InputStream) urlConnection.getContent();
Den Code habe ich 1:1 übernommen und beim Aufruf von
Java:
InputStream content = (InputStream) con.getContent();
lande ich in einer gefühlten Endlosschleife. Ich erhalte weder eine Response noch wird eine Exception geworfen
 
💪 mit der cURL Anfrage bekomme ich die Daten auch übermittelt. Dann gehe ich mal die einzelnen Header durch. Vielleicht habe ich einen vergessen.

Vielen herzlichen Dank 👍
Bevor Du lange suchst: das Timeout bekommst Du, wenn Du mit HTTP/1.1 verbindest.

Hier mal ein lauffähiger Code:
Java:
import java.time.Duration;
import java.net.URI;
import java.net.http.*;

public class Test {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .connectTimeout(Duration.ofSeconds(15))
            .build();

        HttpRequest req = HttpRequest.newBuilder()
            .uri(URI.create("https://api.nasdaq.com/api/quote/KO/option-chain?" + 
                 "assetclass=stocks&limit=60&fromdate=2023-02-17&" +
                 "todate=2023-02-17&excode=oprac&callput=callput&money=at&type=all"))
            .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0")
            .timeout(Duration.ofSeconds(15))
            .build();

        HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandlers.ofString());

        System.out.println(resp.body());
    }
}
 
Bevor Du lange suchst: das Timeout bekommst Du, wenn Du mit HTTP/1.1 verbindest.

Hier mal ein lauffähiger Code:
Java:
import java.time.Duration;
import java.net.URI;
import java.net.http.*;

public class Test {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .connectTimeout(Duration.ofSeconds(15))
            .build();

        HttpRequest req = HttpRequest.newBuilder()
            .uri(URI.create("https://api.nasdaq.com/api/quote/KO/option-chain?" +
                 "assetclass=stocks&limit=60&fromdate=2023-02-17&" +
                 "todate=2023-02-17&excode=oprac&callput=callput&money=at&type=all"))
            .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0")
            .timeout(Duration.ofSeconds(15))
            .build();

        HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandlers.ofString());

        System.out.println(resp.body());
    }
}
Welche java-Version verwendest du? Ich kann leider das Package "java.net.http.*" nicht importieren. Ich selber verwende die Version 19.0.1
 
Du hast also ein Java Projekt erstellt, dann die Test.java reingezogen und jetzt bekommst Du angezeigt, dass Du java.net.http.* nicht importieren kannst? Mit welcher Meldung? Was passiert denn, wenn Du in der Zeile Alt+Enter drückst?

Ansonsten einfach mal auf der Konsole übersetzen und ausführen:
Code:
javac -cp . Test.java
java -cp . Test

Wobei.... bei Java 19 sollte man sich das Übersetzen sogar sparen können:
Code:
java -cp . Test.java
sollte reichen.
 

Zurück
Oben