Browse Source

commit

master
noerw 1 year ago
commit
2465afb716
11 changed files with 183 additions and 0 deletions
  1. 100
    0
      README.md
  2. 1
    0
      daten/kreise.json
  3. 1
    0
      daten/pendler-summary.json
  4. BIN
      daten/pendler.dbf
  5. 1
    0
      daten/pendler.json
  6. 1
    0
      daten/pendler.prj
  7. BIN
      daten/pendler.shp
  8. BIN
      daten/pendler.shx
  9. 15
    0
      fetch-kreise.py
  10. 38
    0
      fetch-pendler.py
  11. 26
    0
      summarize-pendler.py

+ 100
- 0
README.md View File

@@ -0,0 +1,100 @@
1
+# Pendleratlas Scraper
2
+
3
+Die Bundesagentur fuer Arbeit stellt die Pendlerstatistik von 2016 als
4
+interaktive Karte auf ihrer [Website][Pendleratlas] bereit.
5
+
6
+Diese Statistik bietet die detailliertesten Informationen zu Pendlern auf Bundesebene welche ich finden konnte:
7
+Es werden kreisuebergreifende Ein- / Auspendler fuer jeden Kreis, gegliedert nach Pendler-Ziel sowie Geschlecht geliefert.
8
+Ebenfalls ist die Wohnpopulation und Gesamt-Pendlermenge jedes Kreises angegeben.
9
+Anders als in den [Veroeffentlichungen von DeStatis][Destatis] werden hier also auch die exakten Ziel-Kreise der Pendler, sowie exakte Angaben gemacht.
10
+
11
+Daten auf Gemeinde-Ebene mit zusaetzlichen Attributen (Beschaeftigungsart, Wirtschaftsbereich) wie im [Pendleratlas-NRW][PendleratlasNRW] liegen leider nicht vor.
12
+
13
+## PendlerDaten API
14
+Um selbst mit den Daten *arbeiten* zu koennen kann es nuetzlich sein, sie nicht nur auf einer Karte zu betrachten.
15
+Diese python Skripte laden die Pendlerstatistik automatisiert herunter und exportiert sie als GeoJSON bzw Shapefile.
16
+Die zugehoerige API liegt unter `https://statistik.arbeitsagentur.de/PendlerDaten?` ([Beispiel][PendlerBsp]).
17
+
18
+[Pendleratlas]: https://statistik.arbeitsagentur.de/Navigation/Statistik/Statistische-Analysen/Interaktive-Visualisierung/Pendleratlas/Pendleratlas-Nav.html
19
+[Destatis]: https://www-genesis.destatis.de/gis/genView?SRC=4&TABLE=254-39-4
20
+[PendleratlasNRW]: https://www.pendleratlas.nrw.de/
21
+
22
+[PendlerBsp]: https://statistik.arbeitsagentur.de/PendlerData\?type\=ein\&year_month\=201606\&regionInd\=05754\&view\=renderPendler
23
+
24
+> **Disclaimer**: Dieses Projekt ist in keiner Weise mit destatis oder der Arbeitsagentur verbunden. Ich garantiere und hafte fuer nichts bezueglich der hier bereitgestellten Daten und Skripte. Es wurden ausschliesslich oeffentlich zugaengliche APIs dokumentiert.
25
+
26
+### IDs der Kreise
27
+Die API referenziert die Kreise ueber IDs welche von einem ESRI ArcGIS MapServer (?) unter
28
+`http://geois.arbeitsagentur.de/arcgis/rest/services/Gebietsstrukturen/MapServer/3` liegen.
29
+
30
+Dieses Layer laesst sich als GeoJSON mitsamt Kreis IDs, Geometrien und Namen mit folgendem Befehl beziehen:
31
+
32
+```bash
33
+wget "http://geois.arbeitsagentur.de/arcgis/rest/services/Gebietsstrukturen/MapServer/3/query?f=geojson&where=valid_from <= CURRENT_DATE AND valid_to >= CURRENT_DATE&returnGeometry=true&spatialRel=esriSpatialRelIntersects&outFields=ID,region,OBJECTID,parentID&outSR=4326" -O kreise.json
34
+
35
+# oder 
36
+python fetch-kreise.py > kreise.json
37
+```
38
+
39
+> Es stellt sich heraus, dass die von der PendlerDaten API erwarteten Kreis IDs das auf 5-stellen gekuerzte Feld `KN` der Verwaltungsgrenzen (`dvg:nw_dvg2_krs`) des geodatenzentrums sind. Falls also die exakte Geometrie der Kreise benoetigt wird, kann man das sicherlich mit dem offiziellen DVG layer verschneiden.
40
+
41
+[Verwaltungsgrenzen]: https://www.bkg.bund.de/DE/Produkte-und-Services/Shop-und-Downloads/Digitale-Geodaten/Verwaltungsgebiete-Verwaltungsgrenzen/verwaltungsgebiete.html
42
+
43
+### Pendlerdaten
44
+Das Skript `fetch-pendler.py` erwartet die Gemeindegrenzen `kreise.json` im selben Ordner, und fragt die API der Arbeitsagentur fuer jeden Kreis ab.
45
+Dies dauert ne ganze Weile, da die API langsam und instabil ist. Fehlgeschlagene Requests werden wiederholt bis alles da ist.
46
+Das Skript augmentiert das zuvor bezogene `kreise.json` und speichert als `pendler.json`
47
+
48
+Es werden die Attribute `einpendler` und `auspendler` in den Properties jedes Features angelegt.
49
+Diese sehen dann wie folgt aus:
50
+
51
+```js
52
+"properties": {
53
+  "ID": "05910",
54
+  "region": "Hömmelebömmele",
55
+
56
+  // einpendler je kreis ID
57
+  "einpendler": {
58
+    "05913": {
59
+      "frauen": 1838,
60
+      "anzahl": 4573,
61
+      "maenner": 2735
62
+    },
63
+    "05911": {
64
+      "frauen": 1265,
65
+      "anzahl": 3220,
66
+      "maenner": 1955
67
+    },
68
+
69
+    // .... alle anderen kreise
70
+
71
+    // gesamt pendler
72
+    "gesamt": {
73
+      "frauen": 19865,
74
+      "anzahl": 52456,
75
+      "maenner": 32591
76
+    },
77
+    // wohnbevoelkerung des kreises
78
+    "svb": {
79
+      "frauen": 95155,
80
+      "anzahl": 211028,
81
+      "maenner": 115873
82
+    }
83
+  },
84
+
85
+  "einpendler": { ... }
86
+}
87
+```
88
+
89
+### Shapefile
90
+Eine Zusammenfassung der Daten (Pendlergesamtaufkommmen pro Kreis) als Shapefile laesst sich folgendermassen generieren:
91
+
92
+```bash
93
+python summarize-pendler.py
94
+ogr2ogr pendler.shp pendler-summary.json
95
+```
96
+
97
+# Lizenz
98
+- Code: public domain
99
+- pendler.shp, pendler.json, kreise.json: © GeoBasis-DE / BKG 2016 (Daten verändert)
100
+- Pendlerdaten: unbekannt

+ 1
- 0
daten/kreise.json
File diff suppressed because it is too large
View File


+ 1
- 0
daten/pendler-summary.json
File diff suppressed because it is too large
View File


BIN
daten/pendler.dbf View File


+ 1
- 0
daten/pendler.json
File diff suppressed because it is too large
View File


+ 1
- 0
daten/pendler.prj View File

@@ -0,0 +1 @@
1
+GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]

BIN
daten/pendler.shp View File


BIN
daten/pendler.shx View File


+ 15
- 0
fetch-kreise.py View File

@@ -0,0 +1,15 @@
1
+import requests
2
+
3
+kreiseUrl = 'http://geois.arbeitsagentur.de/arcgis/rest/services/Gebietsstrukturen/MapServer/3/query'
4
+kreiseParams = {
5
+        'f' : 'geojson',
6
+        'returnGeometry' : 'true',
7
+        'spatialRel' : 'esriSpatialRelIntersects',
8
+        'outSR' : '4326',
9
+        'outFields' : 'ID,region',
10
+        'where' : 'valid_from <= CURRENT_DATE AND valid_to >= CURRENT_DATE'
11
+        }
12
+
13
+r = requests.get(kreiseUrl, params=kreiseParams)
14
+
15
+print(r.text)

+ 38
- 0
fetch-pendler.py View File

@@ -0,0 +1,38 @@
1
+import requests
2
+import json
3
+
4
+pendlerUrl = 'https://statistik.arbeitsagentur.de/PendlerData'
5
+pendlerParams = { 'year_month' : '201606', 'view' : 'renderPendler' }
6
+
7
+f = open('kreise.json', 'r')
8
+kreise = f.read()
9
+f.close()
10
+geojson = json.loads(kreise)
11
+
12
+while not all('auspendler' in f['properties'] for f in geojson['features']):
13
+    for i in range(len(geojson['features'])):
14
+        f = geojson['features'][i];
15
+
16
+        if 'auspendler' in f['properties']:
17
+            continue
18
+        else:
19
+            print('fetching', f['properties']['ID'], i)
20
+
21
+        pendlerParams['regionInd'] = f['properties']['ID']
22
+
23
+        try:
24
+            pendlerParams['type'] = 'ein'
25
+            r = requests.get(pendlerUrl, params=pendlerParams)
26
+            f['properties']['einpendler'] = json.loads(r.text)
27
+
28
+            pendlerParams['type'] = 'aus'
29
+            r = requests.get(pendlerUrl, params=pendlerParams)
30
+            f['properties']['auspendler'] = json.loads(r.text)
31
+
32
+        except:
33
+            print('errored at', i)
34
+            continue
35
+
36
+f = open('pendler.json', 'w')
37
+f.write(json.dumps(geojson))
38
+f.close()

+ 26
- 0
summarize-pendler.py View File

@@ -0,0 +1,26 @@
1
+import json
2
+
3
+f = open('pendler.json', 'r')
4
+kreise = f.read()
5
+f.close()
6
+geojson = json.loads(kreise)
7
+
8
+for f in geojson['features']:
9
+    f['properties']['poptotal']  = f['properties']['einpendler']['svb']['anzahl']
10
+    f['properties']['popmale']   = f['properties']['einpendler']['svb']['maenner']
11
+    f['properties']['popfemale'] = f['properties']['einpendler']['svb']['frauen']
12
+
13
+    f['properties']['pendintotal']  = f['properties']['einpendler']['gesamt']['anzahl']
14
+    f['properties']['pendinmale']   = f['properties']['einpendler']['gesamt']['maenner']
15
+    f['properties']['pendinfemale'] = f['properties']['einpendler']['gesamt']['frauen']
16
+
17
+    f['properties']['pendouttotal']  = f['properties']['auspendler']['gesamt']['anzahl']
18
+    f['properties']['pendoutmale']   = f['properties']['auspendler']['gesamt']['maenner']
19
+    f['properties']['pendoutfemale'] = f['properties']['auspendler']['gesamt']['frauen']
20
+
21
+    f['properties'].pop('einpendler', None)
22
+    f['properties'].pop('auspendler', None)
23
+
24
+f = open('pendler-summary.json', 'w')
25
+f.write(json.dumps(geojson))
26
+f.close()

Loading…
Cancel
Save