HTML: acquisire dati da una pagine web

ciao a tutti

vorrei scaricare un bollettino meteo da l sito aviation weather, in pratica, inviando dal browser questa richiesta http://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1 ti inviano il metar (bollettino meteo aeronautico) più recente in formato .csv.

La pagina che illustra il servizio è questa AWC - ADDS Text Data Server

Sto adoperando un wemos D1 mini con ide Arduino che poi invierà i dati ad un Arduino duemilanove.

Il problema è che ... non riesco. Ho provato diverse soluzioni ma nessuna ha funzionato, gli errori riportati vanno da 400 "bad request" a 301 " file temporary moved" a richiesta fuori tempo massimo ecc.
Il codice è il seguente:

void loop() {
   if (client.connect("aviationweather.gov/adds/dataserver_current", 80)) {
    Serial.println("connesso al server");
    client.println("GET http://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1 HTTP/1.1");
    client.println("Host:aviationweather.gov/adds/dataserver_current");   
    client.println();
    delay(1000);
    while(client.connected() && !client.available()) delay(1); 
    while (client.available()) {
      int c = client.read();
      String line = client.readStringUntil('\r');
      Serial.print("client read: "); Serial.println(c);
      Serial.print("stringa: "); Serial.println(line);
    }
    client.stop();
    client.flush();
  }
  delay(10000);
}

Nella intestazione c'è i'inizializzazione del client "WiFiClient client" e in void setup() c'è la inizializzazione della seriale e la connessione al wifi.
Questa è la risposta sul monitor seriale:

connesso al server
client read: 72
stringa: TTP/1.1 400 Bad Request
client read: 10
stringa: Server: nginx
client read: 10
stringa: Date: Fri, 11 Jan 2019 09:55:54 GMT
client read: 10
stringa: Content-Type: text/html
client read: 10
stringa: Content-Length: 166
client read: 10
stringa: 
client read: 10
stringa: <html>
client read: 10
stringa: <head><title>400 Bad Request</title></head>
client read: 10
stringa: <body bgcolor="white">
client read: 10
stringa: <center><h1>400 Bad Request</h1></center>
client read: 10
stringa: <hr><center>nginx</center>
client read: 10
stringa: </body>
client read: 10
stringa: </html>

Dove sbaglio?

Grazie in anticipo.

Secondo me devi togliere la riga con cui invii: Host:..., è sbagliata e comunque non serve in questo caso.

Ma visto che sei su un ESP, la cosa più sensata è usare la libreria HTTPClient per fare la richiesta, vedi questo esempio.

grazie per la veloce risposta :slight_smile:
togliendo client.println("Host:aviationweather.gov/adds/dataserver_current"); non funziona, ottengo un errore di timeout:

connesso al server
client read: 72
stringa: TTP/1.0 408 Request Time-out
client read: 10
stringa: Cache-Control: no-cache
client read: 10
stringa: Connection: close
client read: 10
stringa: Content-Type: text/html
client read: 10
stringa: 
client read: 10
stringa: <html><body><h1>408 Request Time-out</h1>
Your browser didn't send a complete request in time.
</body></html>

adesso dò un'occhiata alla libreria HTTPClient... grazie ancora

SukkoPera:
Host:..., è sbagliata e comunque non serve in questo caso.

Scusa, per curiositá, perchè è sbagliata?

Ok, allora evidentemente non è inutile (vuol dire che il server è un virtual host), ma rimane sbagliata, in quanto deve contenere solo appunto l'host (www.aviationweather.gov), non l'intero URL, e deve pure esserci uno spazio dopo i duepunti.

ho modificato la riga host ma... niente, nuovo errore:

connesso al server
client read: 72
stringa: TTP/1.1 302 Moved Temporarily
client read: 10
stringa: Server: nginx
client read: 10
stringa: Date: Fri, 11 Jan 2019 13:47:28 GMT
client read: 10
stringa: Content-Type: text/html
client read: 10
stringa: Content-Length: 154
client read: 10
stringa: Location: http://ricerca.wind.it/?missingurl=www.aviationweather.gov
client read: 10
stringa: 
client read: 10
stringa: <html>
client read: 10
stringa: <head><title>302 Found</title></head>
client read: 10
stringa: <body bgcolor="white">
client read: 10
stringa: <center><h1>302 Found</h1></center>
client read: 10
stringa: <hr><center>nginx</center>
client read: 10
stringa: </body>
client read: 10
stringa: </html>

Ho provato con la libreria ESP8266HTTPClient.h, niente... questo è il codice:

void loop() {
    Serial.print("[HTTP] begin...\n");
    if (http.begin("http://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1")) {  // HTTP
      Serial.print("[HTTP] GET...\n");
      int httpCode = http.GET();
      if (httpCode > 0) {
        Serial.printf("[HTTP] GET... code: %d\n", httpCode);
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          String payload = http.getString();
          Serial.println(payload);
        }
      } else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }
      http.end();
    } else {
      Serial.printf("[HTTP} Unable to connect\n");
    }
  delay(10000);
}

e questa la risposta:

[HTTP] begin...
[HTTP] GET...
[HTTP] GET... code: 301

sicuramente sbaglio qualcosa... ho ricontrollato, se lo invio dal browser mi manda un file a nome "httpparam" con i dati in formato .csv

301 è Moved Permanently, dalla risposta bisognerebbe recuperare un nuovo URL a cui fare la richiesta. Strano che non se ne occupi la librera però.

Dopo quel 301 non stampa altro?

...no

Boh, appena ho tempo provo.

http://www.aviationweather.gov prova https://www.aviationweather.gov
Essendo che non usano piu http

grazie ouassour
anch'io penso che usino https, anche perchè appare analizzando la pagina di risposta, però ho provato e ottengo sempre errore 301.
C'è da dire che se inserisci tutta la frase, con http, nel browser la cosa funziona e scarichi il file.
Secondo me può essere che il reindirizzamento lo faccia il loro server ma non so come farglielo fare.

A naso

    client.println("GET /adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1 HTTP/1.1");
    client.println("Host:aviationweather.gov");

So per certo che se usi GET http non ci va

Edit:
da un esempio che prende il valore dei Bitcoin

  // URI per la richiesta
  String url = "/v1/bpi/currentprice.json";
  
  // Richiesta da inviare al server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");

Come vedi con get viene tolto http:// e l'host mentre viene conservato il resto.

Ah, questo è giustissimo, mi era sfuggito! Bravo zoomx! :slight_smile:

ciao zoomx, grazie per la risposta...
dunque, ho tolto http// ma l'host dal tuo esempio rimane, non viene messo in una singola linea Client.print ma rimane, in pratica:

void loop() {
   if (client.connect("aviationweather.gov", 80)) {
    Serial.println("connesso al server");
    String url = "/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1";
    String host = "aviationweather.gov";
    client.println(String("GET ") + url + "HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");
    delay(1000);
    while(client.connected() && !client.available()) delay(1); 
    while (client.available()) {
      int c = client.read();
      String line = client.readStringUntil('\r');
      Serial.print("client read: "); Serial.println(c);
      Serial.print("stringa: "); Serial.println(line);
    }
    client.stop();
    client.flush();
  }
  delay(7000);
}

giusto?
Purtroppo non funziona, la risposta è:

connesso al server
client read: 72
stringa: TTP/1.0 400 Bad Request
client read: 10
stringa: Server: AkamaiGHost
client read: 10
stringa: Mime-Version: 1.0
client read: 10
stringa: Content-Type: text/html
client read: 10
stringa: Content-Length: 216
client read: 10
stringa: Expires: Sat, 12 Jan 2019 20:57:10 GMT
client read: 10
stringa: Date: Sat, 12 Jan 2019 20:57:10 GMT
client read: 10
stringa: Connection: close
client read: 10
stringa: 
client read: 10
stringa: <HTML><HEAD>
<TITLE>Bad Request</TITLE>
</HEAD><BODY>
<H1>Bad Request</H1>
Your browser sent a request that this server could not understand.<P>
Reference&#32;&#35;7&#46;b7d11597&#46;1547326630&#46;0
</BODY>
</HTML>

:frowning: >:(

client.println(String("GET ") + url + "HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");

Manca uno spazio prima di HTTP, dovrebbe essere " HTTP/1.1\r\n"

giusto! ho corretto ma non è cambiato niente :frowning: :frowning: :frowning:

connesso al server
client read: 72
stringa: TTP/1.1 301 Moved Permanently
client read: 10
stringa: Server: AkamaiGHost
client read: 10
stringa: Content-Length: 0
client read: 10
stringa: Location: https://aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1
client read: 10
stringa: Date: Sat, 12 Jan 2019 21:37:25 GMT
client read: 10
stringa: Connection: close
client read: 10
stringa: 
client read: 10
stringa:

sono diversi giorni che ci provo, ho cambiato tutte le combinazioni possibili senza risultato... c'è probabilmente un reindirizzamento che non riesco a capire

hmmmm ho provato sia con curl che wget, ottengo questo

Cmdlet Invoke-WebRequest nella posizione 1 della pipeline dei comandi
Specificare i valori per i seguenti parametri:
Uri: http://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1


StatusCode        : 200
StatusDescription : OK
Content           : {78, 111, 32, 101...}
RawContent        : HTTP/1.1 200 OK
                    X-Frame-Options: SAMEORIGIN
                    X-Content-Type-Options: nosniff
                    X-XSS-Protection: 1; mode=block
                    Strict-Transport-Security: max-age=63072000; includeSubdomains;
                    Connection: keep-alive...
Headers           : {[X-Frame-Options, SAMEORIGIN], [X-Content-Type-Options, nosniff], [X-XSS-Protection, 1;
                    mode=block], [Strict-Transport-Security, max-age=63072000; includeSubdomains;]...}
RawContentLength  : 988

e non scarica nulla ma ho scoperto che si tratta di quelli integrati in PowerShell di Windows 10.
Usando Wget e il prompt dei comandi ottengo questo

D:\Programmi\wget-1.20-win64>wget "http://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1"
--2019-01-12 23:50:26--  http://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1
Resolving www.aviationweather.gov (www.aviationweather.gov)... 92.122.200.236
Connecting to www.aviationweather.gov (www.aviationweather.gov)|92.122.200.236|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1 [following]
--2019-01-12 23:50:26--  https://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1
Connecting to www.aviationweather.gov (www.aviationweather.gov)|92.122.200.236|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 988 [application/x-csv]
Saving to: 'httpparam@dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1'

httpparam@dataSource=metars&r 100%[=================================================>]     988  --.-KB/s    in 0s

2019-01-12 23:50:26 (4,28 MB/s) - 'httpparam@dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1' saved [988/988]

Il metar viene scaricato ma leggendo i messaggi di wget si vede che il sito redirige la richiesta su https.
A questo punto c'è da studiare l'esempio HTTPSRequest.ino che, appunto, si trova fra gli esempi.

Bravo zoomx! bell'idea usare wget!
Avevo anche provato a connettermi a https con un certificato ma senza risultato, adesso mi guardo HTTPSRequest.ino
Grazie ancora!!!

Finalmente funziona!! Per chi fosse interessato questo è il codice ridotto all'osso:

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>

const char ssid[] = "........";           // SSID of your home WiFi
const char pass[] = "........";            // password of your home WiFi
const String host = "aviationweather.gov";
const String url = "/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&stationString=LIML&hoursBeforeNow=1";
const int porta = 443;

WiFiClientSecure client;

void setup() {
  Serial.begin(115200);               // only for debug
  WiFi.begin(ssid, pass);             // connects to the WiFi router
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("connesso");
}
void loop() {
   if (client.connect(host, porta)) {
    Serial.println("connesso al server");
  
    client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: BuildFailureDetectorESP8266\r\n" + "Connection: close\r\n\r\n");
    delay(1000);

    while(client.connected() && !client.available()) delay(1); 
    while (client.available()) {
      int c = client.read();
      String line = client.readStringUntil('\r');
      Serial.print("client read: "); Serial.println(c);
      Serial.print("stringa: "); Serial.println(line);
    }
    client.stop();
    client.flush();
  }
  delay(10000);
}

e questa la risposta del server:

connesso al server
client read: 72
stringa: TTP/1.1 200 OK
client read: 10
stringa: Server: Apache-Coyote/1.1
client read: 10
stringa: X-Frame-Options: SAMEORIGIN
client read: 10
stringa: X-Content-Type-Options: nosniff
client read: 10
stringa: X-XSS-Protection: 1; mode=block
client read: 10
stringa: Strict-Transport-Security: max-age=63072000; includeSubdomains;
client read: 10
stringa: Content-Type: application/x-csv
client read: 10
stringa: Date: Sun, 13 Jan 2019 14:48:03 GMT
client read: 10
stringa: Content-Length: 1005
client read: 10
stringa: Connection: close
client read: 10
stringa: 
client read: 10
stringa: No errors
No warnings
4 ms
data source=metars
2 results
raw_text,station_id,observation_time,latitude,longitude,temp_c,dewpoint_c,wind_dir_degrees,wind_speed_kt,wind_gust_kt,visibility_statute_mi,altim_in_hg,sea_level_pressure_mb,corrected,auto,auto_station,maintenance_indicator_on,no_signal,lightning_sensor_off,freezing_rain_sensor_off,present_weather_sensor_off,wx_string,sky_cover,cloud_base_ft_agl,sky_cover,cloud_base_ft_agl,sky_cover,cloud_base_ft_agl,sky_cover,cloud_base_ft_agl,flight_category,three_hr_pressure_tendency_mb,maxT_c,minT_c,maxT24hr_c,minT24hr_c,precip_in,pcp3hr_in,pcp6hr_in,pcp24hr_in,snow_in,vert_vis_ft,metar_type,elevation_m
LIML 131420Z 15003KT 7000 SCT080 06/00 Q1009 NOSIG,LIML,2019-01-13T14:20:00Z,45.47,9.27,6.0,0.0,150,3,,4.35,29.793306,,,,,,TRUE,,,,,SCT,8000,,,,,,,MVFR,,,,,,,,,,,,METAR,103.0
LIML 131350Z 13004KT 090V170 7000 NSC 06/00 Q1009 NOSIG,LIML,2019-01-13T13:50:00Z,45.47,9.27,6.0,0.0,130,4,,4.35,29.793306,,,,,,TRUE,,,,,CLR,,,,,,,,MVFR,,,,,,,,,,,,METAR,103.0

nell'esempio HTTPSRequest si fa uso del fingerprint ...che non funziona, nel senso che è scaduto e dà: certificate doesn't match, ho provato ad ottenere un fingerprint valido così:

echo | openssl s_client -connect script.google.com:443 | openssl x509 -fingerprint -noout

ed in effetti ho ottenuto un nuovo SHA1 Fingerprint ...che non funziona neanche lui, però alla fine il sever mi dà ugualmente il dato che mi serve, così ho provato ad eliminare il problema fingerprint ed in effetti funziona.
Non so esattamente questo cosa comporti e se qualcuno potesse spiegarlo ne sarei grato...

Vorrei ringraziare tutti quelli che si sono interessati al mio problema ed in particolare zoomx che mi ha dato le giuste indicazioni.
Dario