Kürzlich wurde eine afrikanische Open-Data-Portal-Site namens openAFRICA von einer Organisation namens Code for Africa und einer eigenen Wasserversorgung in Ruanda betrieben Die automatische Verknüpfungsfunktion von Wasservektor-Kacheldaten, die gemeinsam mit der Aktiengesellschaft WASAC verwaltet wird, wurde in Python implementiert.
Da es eine API namens CKAN verwendet, die anscheinend auf Open-Data-Sites japanischer Kommunalverwaltungen weit verbreitet ist, kann sie meiner Meinung nach verwendet werden, wenn Sie offene Daten wie Dateien, die Ihrer Organisation gehören, automatisch über die API verknüpfen möchten. Also möchte ich es teilen.
In diesem Artikel wird Github Action verwendet, wenn die geöffneten Daten auf Github aktualisiert werden, um die Daten auf der Plattform automatisch über CKAN zu verknüpfen.
Die openAFRICA-Seite mit den offenen Daten der Wasservektor-Kachel der Ruanda Water Authority finden Sie übrigens unter folgendem Link. https://open.africa/dataset/rw-water-vectortiles
Darüber hinaus befindet sich das Github-Repository für Wasservektorkacheln unter dem folgenden Link und wird jede Woche vom Server des öffentlichen Amtes des Wasserwerks automatisch auf Github aktualisiert. https://github.com/WASAC/vt
Wenn pipenv nicht installiert ist, stellen Sie es bitte zuerst ein.
git clone https://github.com/watergis/open-africa-uploader
cd open-africa-uploader
pipenv install
pipenv shell
Zuerst werde ich den vollständigen Quellcode von "OpenAfricaUploader.py" im Repository veröffentlichen.
import os
import ckanapi
import requests
class OpanAfricaUploader(object):
def __init__(self, api_key):
"""Constructor
Args:
api_key (string): CKAN api key
"""
self.data_portal = 'https://africaopendata.org'
self.APIKEY = api_key
self.ckan = ckanapi.RemoteCKAN(self.data_portal, apikey=self.APIKEY)
def create_package(self, url, title):
"""create new package if it does not exist yet.
Args:
url (str): the url of package eg. https://open.africa/dataset/{package url}
title (str): the title of package
"""
package_name = url
package_title = title
try:
print ('Creating "{package_title}" package'.format(**locals()))
self.package = self.ckan.action.package_create(name=package_name,
title=package_title,
owner_org = 'water-and-sanitation-corporation-ltd-wasac')
except (ckanapi.ValidationError) as e:
if (e.error_dict['__type'] == 'Validation Error' and
e.error_dict['name'] == ['That URL is already in use.']):
print ('"{package_title}" package already exists'.format(**locals()))
self.package = self.ckan.action.package_show(id=package_name)
else:
raise
def resource_create(self, data, path, api="/api/action/resource_create"):
"""create new resource, or update existing resource
Args:
data (object): data for creating resource. data must contain package_id, name, format, description. If you overwrite existing resource, id also must be included.
path (str): file path for uploading
api (str, optional): API url for creating or updating. Defaults to "/api/action/resource_create". If you want to update, please specify url for "/api/action/resource_update"
"""
self.api_url = self.data_portal + api
print ('Creating "{}"'.format(data['name']))
r = requests.post(self.api_url,
data=data,
headers={'Authorization': self.APIKEY},
files=[('upload', open(path, 'rb'))])
if r.status_code != 200:
print ('Error while creating resource: {0}'.format(r.content))
else:
print ('Uploaded "{}" successfully'.format(data['name']))
def resource_update(self, data, path):
"""update existing resource
Args:
data (object): data for creating resource. data must contain id, package_id, name, format, description.
path (str): file path for uploading
"""
self.resource_create(data, path, "/api/action/resource_update")
def upload_datasets(self, path, description):
"""upload datasets under the package
Args:
path (str): file path for uploading
description (str): description for the dataset
"""
filename = os.path.basename(path)
extension = os.path.splitext(filename)[1][1:].lower()
data = {
'package_id': self.package['id'],
'name': filename,
'format': extension,
'description': description
}
resources = self.package['resources']
if len(resources) > 0:
target_resource = None
for resource in reversed(resources):
if filename == resource['name']:
target_resource = resource
break
if target_resource == None:
self.resource_create(data, path)
else:
print ('Resource "{}" already exists, it will be overwritten'.format(target_resource['name']))
data['id'] = target_resource['id']
self.resource_update(data, path)
else:
self.resource_create(data, path)
Der Quellcode zum Aufrufen von "OpenAfricaUploader.py" zum Hochladen einer Datei sieht folgendermaßen aus:
import os
from OpenAfricaUploader import OpanAfricaUploader
uploader = OpanAfricaUploader(args.key)
uploader.create_package('rw-water-vectortiles','Vector Tiles for rural water supply systems in Rwanda')
uploader.upload_datasets(os.path.abspath('../data/rwss.mbtiles'), 'mbtiles format of Mapbox Vector Tiles which was created by tippecanoe.')
Ich werde eins nach dem anderen erklären.
Für dieses Modul wurde die URL der Basisportal-Site im Voraus im Konstruktor festgelegt, um sie auf openAFRICA hochzuladen.
Ersetzen Sie die URL im Teil von "self.data_portal =" https: // africaopendata.org "durch die URL der von Ihrer Organisation verwendeten CKAN-API.
def __init__(self, api_key):
"""Constructor
Args:
api_key (string): CKAN api key
"""
self.data_portal = 'https://africaopendata.org'
self.APIKEY = api_key
self.ckan = ckanapi.RemoteCKAN(self.data_portal, apikey=self.APIKEY)
Der Aufruf des Konstruktors sieht folgendermaßen aus: Geben Sie den CKAN-API-Schlüssel für Ihr Konto in "args.key" an.
uploader = OpanAfricaUploader(args.key)
Erstellen Sie ein Paket mit der API package_create. Geben Sie zu diesem Zeitpunkt im Argument Folgendes an.
--name = Die hier angegebene Zeichenfolge ist die URL des Pakets --title = Pakettitel --owner_org = ID der Zielorganisation im CKAN-Portal
Wenn die Erstellung erfolgreich ist, werden die Paketinformationen als Rückgabewert zurückgegeben. Wenn es bereits vorhanden ist, tritt ein Fehler auf. Daher schreibe ich einen Prozess, um die vorhandenen Paketinformationen im Ausnahmeprozess abzurufen.
def create_package(self, url, title):
"""create new package if it does not exist yet.
Args:
url (str): the url of package eg. https://open.africa/dataset/{package url}
title (str): the title of package
"""
package_name = url
package_title = title
try:
print ('Creating "{package_title}" package'.format(**locals()))
self.package = self.ckan.action.package_create(name=package_name,
title=package_title,
owner_org = 'water-and-sanitation-corporation-ltd-wasac')
except (ckanapi.ValidationError) as e:
if (e.error_dict['__type'] == 'Validation Error' and
e.error_dict['name'] == ['That URL is already in use.']):
print ('"{package_title}" package already exists'.format(**locals()))
self.package = self.ckan.action.package_show(id=package_name)
else:
raise
Diese Funktion kann wie folgt aufgerufen werden
uploader.create_package('rw-water-vectortiles','Vector Tiles for rural water supply systems in Rwanda')
Ressourcen werden mit einer Funktion namens "resource_create" erstellt. Sie können die REST-API / api / action / resource_create
verwenden, um die hochzuladenden Binärdaten und Dateiinformationen zu übergeben.
def resource_create(self, data, path, api="/api/action/resource_create"):
self.api_url = self.data_portal + api
print ('Creating "{}"'.format(data['name']))
r = requests.post(self.api_url,
data=data,
headers={'Authorization': self.APIKEY},
files=[('upload', open(path, 'rb'))])
if r.status_code != 200:
print ('Error while creating resource: {0}'.format(r.content))
else:
print ('Uploaded "{}" successfully'.format(data['name']))
Wenn Sie jedoch nur "resource_create" verwenden, können Sie nur Ressourcen hinzufügen, und die Anzahl steigt bei jedem Update stetig an. Verwenden Sie daher die API "/ api / action / resource_update", um zu aktualisieren, wenn vorhandene Ressourcen vorhanden sind. Ich werde das machen.
Die Verwendung von "resource_update" ist im Grunde die gleiche wie "resource_create". Der einzige Unterschied besteht darin, ob "resource_id" in "data" enthalten ist oder nicht.
def resource_update(self, data, path):
self.resource_create(data, path, "/api/action/resource_update")
Eine Funktion namens "upload_datasets" kombiniert "resource_create" und "resource_update" auf eine nette Weise, um vorhandene Ressourcen zu aktualisieren, falls vorhanden, und neue zu erstellen, wenn sie nicht vorhanden sind.
def upload_datasets(self, path, description):
#Trennen Sie den Dateinamen von der Erweiterung
filename = os.path.basename(path)
extension = os.path.splitext(filename)[1][1:].lower()
#Erstellen Sie Daten für die Ressourcenerstellung
data = {
'package_id': self.package['id'], #Paket-ID
'name': filename, #Dateiname aktualisiert werden
'format': extension, #Format (hier Erweiterung)
'description': description #Dateibeschreibung
}
#Wenn das Paket bereits eine Ressource enthält, prüfen Sie, ob eine Ressource mit demselben Namen wie der hochzuladende Dateiname vorhanden ist.
resources = self.package['resources']
if len(resources) > 0:
target_resource = None
for resource in reversed(resources):
if filename == resource['name']:
target_resource = resource
break
if target_resource == None:
#Ressource, wenn keine Ressource mit demselben Namen vorhanden ist_Rufen Sie create an
self.resource_create(data, path)
else:
#Wenn eine Ressource vorhanden ist, legen Sie die ID in Daten und Ressource fest_Update aufrufen
print ('Resource "{}" already exists, it will be overwritten'.format(target_resource['name']))
data['id'] = target_resource['id']
self.resource_update(data, path)
else:
#Ressource, wenn keine Ressource_Rufen Sie create an
self.resource_create(data, path)
Die Funktion upload_datasets
kann wie folgt aufgerufen werden.
uploader.upload_datasets(os.path.abspath('../data/rwss.mbtiles'), 'mbtiles format of Mapbox Vector Tiles which was created by tippecanoe.')
Sie können es über die Befehlszeile mit "upload2openafrica.py" aufrufen.
import os
import argparse
from OpenAfricaUploader import OpanAfricaUploader
def get_args():
prog = "upload2openafrica.py"
usage = "%(prog)s [options]"
parser = argparse.ArgumentParser(prog=prog, usage=usage)
parser.add_argument("--key", dest="key", help="Your CKAN api key", required=True)
parser.add_argument("--pkg", dest="package", help="Target url of your package", required=True)
parser.add_argument("--title", dest="title", help="Title of your package", required=True)
parser.add_argument("--file", dest="file", help="Relative path of file which you would like to upload", required=True)
parser.add_argument("--desc", dest="description", help="any description for your file", required=True)
args = parser.parse_args()
return args
if __name__ == "__main__":
args = get_args()
uploader = OpanAfricaUploader(args.key)
uploader.create_package(args.package,args.title)
uploader.upload_datasets(os.path.abspath(args.file), args.description)
Wenn Sie es tatsächlich verwenden, sieht es wie folgt aus. Ich mache ein Shell-Skript namens "upload_mbtiles.sh". Stellen Sie sicher, dass die Umgebungsvariable auf "CKAN_API_KEY" gesetzt ist.
#!/bin/bash
pipenv run python upload2openafrica.py \
--key ${CKAN_API_KEY} \
--pkg rw-water-vectortiles \
--title "Vector Tiles for rural water supply systems in Rwanda" \
--file ../data/rwss.mbtiles \
--desc "mbtiles format of Mapbox Vector Tiles which was created by tippecanoe."
Sie können jetzt offene Daten mit der CKAN-API hochladen.
Es ist jedoch schwierig, jedes Mal manuell eine Verbindung mit CKAN herzustellen, daher werde ich es mit Github Action automatisieren. Die Workflow-Datei sieht folgendermaßen aus:
name: openAFRICA upload
on:
push:
branches: [ master ]
#Hier wird der Workflow ausgeführt, wenn der Datenordner und darunter aktualisiert werden.
paths:
- "data/**"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install dependencies
#Nehmen Sie zunächst die Grundeinstellungen für Pipenv vor.
run: |
cd scripts
pip install pipenv
pipenv install
- name: upload to openAFRICA
#CKAN in Secrets auf der Seite Einstellungen des Github-Repositorys_API_Wenn Sie sich mit dem Namen KEY registrieren, können Sie Umgebungsvariablen wie folgt verwenden.
env:
CKAN_API_KEY: ${{secrets.CKAN_API_KEY}}
#Danach werde ich das Shell-Skript aufrufen
run: |
cd scripts
./upload_mbtiles.sh
Allein damit kann die Datei nach dem Hochladen auf Github automatisch mit der offenen Datenplattform verknüpft werden. Das folgende Bild zeigt den Bildschirm, auf dem Github Aciton von der Ruanda Water Authority ausgeführt wird.
Die CKAN-API wird auf verschiedenen Open Source-Plattformen im In- und Ausland verwendet. Die CKAN-API kann die Datenverknüpfung mithilfe von Python relativ einfach implementieren. Wenn die geöffneten Daten auf Github verwaltet werden, können sie mithilfe von Github Action einfacher und automatischer verknüpft werden.
Wir hoffen, dass das für openAFRICA erstellte Modul für die Nutzung offener Daten mit anderen CKANs in Japan und Übersee nützlich sein wird.
Recommended Posts