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 @@
# Pendleratlas Scraper

Die Bundesagentur fuer Arbeit stellt die Pendlerstatistik von 2016 als
interaktive Karte auf ihrer [Website][Pendleratlas] bereit.

Diese Statistik bietet die detailliertesten Informationen zu Pendlern auf Bundesebene welche ich finden konnte:
Es werden kreisuebergreifende Ein- / Auspendler fuer jeden Kreis, gegliedert nach Pendler-Ziel sowie Geschlecht geliefert.
Ebenfalls ist die Wohnpopulation und Gesamt-Pendlermenge jedes Kreises angegeben.
Anders als in den [Veroeffentlichungen von DeStatis][Destatis] werden hier also auch die exakten Ziel-Kreise der Pendler, sowie exakte Angaben gemacht.

Daten auf Gemeinde-Ebene mit zusaetzlichen Attributen (Beschaeftigungsart, Wirtschaftsbereich) wie im [Pendleratlas-NRW][PendleratlasNRW] liegen leider nicht vor.

## PendlerDaten API
Um selbst mit den Daten *arbeiten* zu koennen kann es nuetzlich sein, sie nicht nur auf einer Karte zu betrachten.
Diese python Skripte laden die Pendlerstatistik automatisiert herunter und exportiert sie als GeoJSON bzw Shapefile.
Die zugehoerige API liegt unter `https://statistik.arbeitsagentur.de/PendlerDaten?` ([Beispiel][PendlerBsp]).

[Pendleratlas]: https://statistik.arbeitsagentur.de/Navigation/Statistik/Statistische-Analysen/Interaktive-Visualisierung/Pendleratlas/Pendleratlas-Nav.html
[Destatis]: https://www-genesis.destatis.de/gis/genView?SRC=4&TABLE=254-39-4
[PendleratlasNRW]: https://www.pendleratlas.nrw.de/

[PendlerBsp]: https://statistik.arbeitsagentur.de/PendlerData\?type\=ein\&year_month\=201606\&regionInd\=05754\&view\=renderPendler

> **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.

### IDs der Kreise
Die API referenziert die Kreise ueber IDs welche von einem ESRI ArcGIS MapServer (?) unter
`http://geois.arbeitsagentur.de/arcgis/rest/services/Gebietsstrukturen/MapServer/3` liegen.

Dieses Layer laesst sich als GeoJSON mitsamt Kreis IDs, Geometrien und Namen mit folgendem Befehl beziehen:

```bash
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

# oder
python fetch-kreise.py > kreise.json
```

> 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.

[Verwaltungsgrenzen]: https://www.bkg.bund.de/DE/Produkte-und-Services/Shop-und-Downloads/Digitale-Geodaten/Verwaltungsgebiete-Verwaltungsgrenzen/verwaltungsgebiete.html

### Pendlerdaten
Das Skript `fetch-pendler.py` erwartet die Gemeindegrenzen `kreise.json` im selben Ordner, und fragt die API der Arbeitsagentur fuer jeden Kreis ab.
Dies dauert ne ganze Weile, da die API langsam und instabil ist. Fehlgeschlagene Requests werden wiederholt bis alles da ist.
Das Skript augmentiert das zuvor bezogene `kreise.json` und speichert als `pendler.json`

Es werden die Attribute `einpendler` und `auspendler` in den Properties jedes Features angelegt.
Diese sehen dann wie folgt aus:

```js
"properties": {
"ID": "05910",
"region": "Hömmelebömmele",

// einpendler je kreis ID
"einpendler": {
"05913": {
"frauen": 1838,
"anzahl": 4573,
"maenner": 2735
},
"05911": {
"frauen": 1265,
"anzahl": 3220,
"maenner": 1955
},

// .... alle anderen kreise

// gesamt pendler
"gesamt": {
"frauen": 19865,
"anzahl": 52456,
"maenner": 32591
},
// wohnbevoelkerung des kreises
"svb": {
"frauen": 95155,
"anzahl": 211028,
"maenner": 115873
}
},

"einpendler": { ... }
}
```

### Shapefile
Eine Zusammenfassung der Daten (Pendlergesamtaufkommmen pro Kreis) als Shapefile laesst sich folgendermassen generieren:

```bash
python summarize-pendler.py
ogr2ogr pendler.shp pendler-summary.json
```

# Lizenz
- Code: public domain
- pendler.shp, pendler.json, kreise.json: © GeoBasis-DE / BKG 2016 (Daten verändert)
- 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 @@
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 @@
import requests

kreiseUrl = 'http://geois.arbeitsagentur.de/arcgis/rest/services/Gebietsstrukturen/MapServer/3/query'
kreiseParams = {
'f' : 'geojson',
'returnGeometry' : 'true',
'spatialRel' : 'esriSpatialRelIntersects',
'outSR' : '4326',
'outFields' : 'ID,region',
'where' : 'valid_from <= CURRENT_DATE AND valid_to >= CURRENT_DATE'
}

r = requests.get(kreiseUrl, params=kreiseParams)

print(r.text)

+ 38
- 0
fetch-pendler.py View File

@@ -0,0 +1,38 @@
import requests
import json

pendlerUrl = 'https://statistik.arbeitsagentur.de/PendlerData'
pendlerParams = { 'year_month' : '201606', 'view' : 'renderPendler' }

f = open('kreise.json', 'r')
kreise = f.read()
f.close()
geojson = json.loads(kreise)

while not all('auspendler' in f['properties'] for f in geojson['features']):
for i in range(len(geojson['features'])):
f = geojson['features'][i];

if 'auspendler' in f['properties']:
continue
else:
print('fetching', f['properties']['ID'], i)

pendlerParams['regionInd'] = f['properties']['ID']

try:
pendlerParams['type'] = 'ein'
r = requests.get(pendlerUrl, params=pendlerParams)
f['properties']['einpendler'] = json.loads(r.text)

pendlerParams['type'] = 'aus'
r = requests.get(pendlerUrl, params=pendlerParams)
f['properties']['auspendler'] = json.loads(r.text)

except:
print('errored at', i)
continue

f = open('pendler.json', 'w')
f.write(json.dumps(geojson))
f.close()

+ 26
- 0
summarize-pendler.py View File

@@ -0,0 +1,26 @@
import json

f = open('pendler.json', 'r')
kreise = f.read()
f.close()
geojson = json.loads(kreise)

for f in geojson['features']:
f['properties']['poptotal'] = f['properties']['einpendler']['svb']['anzahl']
f['properties']['popmale'] = f['properties']['einpendler']['svb']['maenner']
f['properties']['popfemale'] = f['properties']['einpendler']['svb']['frauen']

f['properties']['pendintotal'] = f['properties']['einpendler']['gesamt']['anzahl']
f['properties']['pendinmale'] = f['properties']['einpendler']['gesamt']['maenner']
f['properties']['pendinfemale'] = f['properties']['einpendler']['gesamt']['frauen']

f['properties']['pendouttotal'] = f['properties']['auspendler']['gesamt']['anzahl']
f['properties']['pendoutmale'] = f['properties']['auspendler']['gesamt']['maenner']
f['properties']['pendoutfemale'] = f['properties']['auspendler']['gesamt']['frauen']

f['properties'].pop('einpendler', None)
f['properties'].pop('auspendler', None)

f = open('pendler-summary.json', 'w')
f.write(json.dumps(geojson))
f.close()

Loading…
Cancel
Save