Gunnar Bittersmann: Adresse zu Geo-Koordinaten

Ich habe Adressdaten als JSON-LD/Schema.org, bspw. die Adresse der Scheinbar:

{
	"@context": {
		"@vocab": "http://schema.org/"
	},
	"@type": "Place",
	"name": "Scheinbar Varieté",
	"address": {
		"@type": "PostalAddress",
		"streetAddress": "Monumentenstraße 9",
		"postalCode": "10829",
		"addressLocality": "Berlin"
	}
}

Nun möchte ich die Geo-Koordinaten hinzufügen; das soll dann so aussehen:

{
	"@context": {
		"@vocab": "http://schema.org/"
	},
	"@type": "Place",
	"name": "Scheinbar Varieté",
	"address": {
		"@type": "PostalAddress",
		"streetAddress": "Monumentenstraße 9",
		"postalCode": "10829",
		"addressLocality": "Berlin"
	},
	"geo": {
		"@type": "GeoCoordinates",
		"latitude": "52.488119",
		"longitude": "13.366704"
	}
}

Mit Diensten wie gpskoordinaten.de könnte ich mir dir Koordinaten zusammensuchen. Da es sich aber um etwa 400 Adressen handelt, wäre das ein abendfüllendes Programm.

Also muss eine programmatische Lösung her. Sowas wie Googles Geocoding API anzapfen. Dazu müsste ich mir wohl oder übel „einen Google Account erstellen und einen API-Key anfordern. Das kostet natürlich nichts (außer dass ihr eure Seele an Google verkauft…)“, wie Thomas Christlieb schreibt.

Google wäre nicht Google, wenn die nicht eine Verbindung zwischen den 400 Adressen herstellen würden …

Welche Optionen habe ich, Google nicht meine Seele und die Adressdaten auszuliefern? Welche anderen derartigen Dienste gibt es? Sind die genauso gut wie Google Maps (oder gar besser)?

LLAP 🖖

--
„Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
  1. Hallo Gunnar,

    hast Du Dir schon Open Street Map angeschaut?

    Könntest Du alternativ ein Scriptlet in gpskoordinaten.de injizieren, das die Seite scriptet?

    Rolf

    --
    sumpsi - posui - clusi
    1. @@Rolf B

      hast Du Dir schon Open Street Map angeschaut?

      Bei meiner Suche war ich zunächst nur auf diese Uralt-Wiki-Seite gestoßen. Aber da gibt ja auch ein paar Links, denen ich jetzt mal gefolgt bin …

      Zwei, drei Clicks weiter war ich bei der Masterarbeit Effiziente Georeferenzierung mit OpenStreetMap-Daten von Markus Weber; von dort gings dann zu Nominatim, was auch dokumentiert ist.

      Mal testweise den Query street=Monumentenstraße%209&postalcode=10829&city=Berlin&format=json probiert; in der Antwort findet sich "lat":"52.488182","lon":"13.3667776".

      Die Abweichung zu Googles Ergebnis beträgt – wenn ich mich nicht verrechnet habe – etwa 20 cm in Nord-Süd-Richtung und 2 Meter in Ost-West-Richtung, was in der Scheinbar so etwa die halbe Entfernung vom Eingang bis zur Bühne ist; damit kann ich leben. 😉

      OSM verortet die Scheinbar weiter östlich als Google. Tatsächlich ist die Bühne vom Eingang aus aber in westlicher Richtung. Ich hätte das andersrum vermutet: dass G$$gle die Dollarzeichen in den Pupillen hat und sich OSM kunstinteressiert zeigt.

      Dann muss ich mir ja nur noch ein Script (PHP?) bauen, dass die JSON-LD-Dateien (etwa 20 an der Zahl) nacheinander abarbeitet: einlesen, Adressdaten (etwa 20 pro Datei) extrahieren, jeweils Query an Nominatim schicken, Antwort parsen, Koordinaten ins JSON-LD einbauen und die geänderte Datei speichern.

      LLAP 🖖

      --
      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      1. Hallo Gunnar,

        Zwei, drei Clicks weiter war ich bei der Masterarbeit Effiziente Georeferenzierung mit OpenStreetMap-Daten von Markus Weber; von dort gings dann zu Nominatim, was auch dokumentiert ist.

        das würde ich auch nehmen. Alternativ oder auch zum Feintuning könntest du auch aus diesem Artikel das letze Beispiel nehmen, um dir zu einem Mausklick in der Karte die Geokoordinaten anzeigen zu lassen. Bei dieser Karte habe ich mir die Koordinaten so besorgt.

        Gruß
        Jürgen

          1. Nominatim hat auch eine brauchbare API.

            wie Gunnar schon schrieb.

            1. Test:

              Ich hab das vor gefühlten 100 Jahren schon mal geschrieben, weil da das Thema Adresskorrektur/Adressverifizierung anstand.

              Damals noch mit Google, man brauchte keinen Key.

              Fazit: Google war schneller und manchmal liefert der Server keine Ergebnisse. Sekunden später dann doch.

            2. @@JürgenB

              Nominatim hat auch eine brauchbare API.

              wie Gunnar schon schrieb.

              Ich würde niemals schreiben, dass etwas eine brauchbare API hätte. 😉

              Das API, ein brauchbares.

              LLAP 🖖

              --
              „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
              1. Da der Server "sehr empfindlich" ist hier mal als Ausriss ein Teil des vorläufigen Ergebnisses meiner Bemühungen um STABIL andere ( und dann verwertbare ) Antworten als einen "403er" zu erhalten:

                <?php
                
                error_reporting( E_ERROR );
                if ( isset( $_REQUEST['adresse'] ) && $_REQUEST['adresse'] ) {
                    $ort = urlencode( $_REQUEST['adresse'] );
                    $agents[]  = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0';
                    $agents[]  = 'Mozilla/5.0 (Windows i686; rv:64.0) Gecko/20100101 Firefox/64.0';
                    $agents[]  = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36';
                    $fakeAgent = $agents[rand( 0, count( $agents )-1 )];
                    $fakeIp    = rand( 1, 250 ) . '.' . rand( 1, 254 ) . '.' . rand( 1, 254 ) . '.'.rand( 1, 254 );
                
                	$ch = curl_init( "https://nominatim.openstreetmap.org/?format=json&addressdetails=1&q=$ort&limit=10" );
                	curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
                	curl_setopt( $ch, CURLOPT_HEADER, 0 );
                	curl_setopt( $ch, CURLOPT_FORBID_REUSE, true) ;
                	curl_setopt( $ch, CURLOPT_USERAGENT, $fakeAgent );
                	if ( defined( CURLOPT_ENCODING ) ) {
                		curl_setopt( $ch, CURLOPT_ENCODING, '' ); # ab PHP 7.1 endet alle unterstützten Kodierungen wie identity, deflate und gzip.
                	}
                	
                	if ( isset ( $_SERVER['HTTP_REFERER'] ) ) {
                		curl_setopt( $ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER'] );
                	}
                	
                	$header[] = "Accept: application/json,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
                	$header[] = "Cache-Control: max-age=0";
                	$header[] = "Connection: keep-alive";
                	$header[] = "Keep-Alive: 300";
                	$header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
                	$header[] = "Accept-Language: en-us,en;q=0.5";
                	$header[] = "Pragma: "; // browsers keep this blank. 
                	$header[] = "X-Forwarded-For: $fakeIp"; // Play as proxy
                	
                	curl_setopt( $curl, CURLOPT_HTTPHEADER, $header ); 
                
                
                	$trys = 0;
                	$daten = '';
                	$responseCode = 0;
                
                    while ( 200 != $responseCode && $trys < 5 )  {
                		$daten = curl_exec( $ch );
                		if ( curl_errno( $ch ) ) {
                			echo "<pre>", curl_​error( $ch ); exit;
                		}
                		$responseCode = curl_getinfo( $ch, CURLINFO_RESPONSE_CODE );
                		if ( 200 != $responseCode ) {
                			time_nanosleep ( 1, 500000000 ); # 1,5 Sekunden
                		}
                    }
                	
                	
                	if ( 200 != $responseCode  ) {
                		echo "<p>Sorry! Responce Code ist auch nach 5 Versuchen $responseCode - Versuchen Sie es in ein paar Sekunden noch einmal.</p>";
                		exit;
                	}
                	
                	curl_close( $ch );
                	
                    #echo "<pre>"; print_r( $daten ); exit;
                #*/
                
                    if ( $daten ) {
                		$daten = json_decode( $daten , true );
                		foreach ( $daten as $item ) {
                			
                			if ( isset( $item['address']['city'] )  )
                          { $item['address']['county']  = $item['address']['city']; }
                			if ( isset( $item['address']['city_district'] )  ) 
                          { $item['address']['suburb']  = $item['address']['city_district']; }
                
                1. Ergebnis der Bemühungen:

                  Monumentenstr.+9,+10829+Berlin

                  Ich frage mich gerade ob man das Ergebnis nicht besser cachen sollte. Und wenn ja wie? Querry trimmen, in kleinbuchstaben umwandeln, dann "md5-en" und mit JSON + ZeitpunktErmittlung + LetzteAbfrage in einer Datenbank?

  2. Nun, wenn Dir die Google-API nicht lieb ist und die Adressen in Deutschland liegen, dann gibt es noch die