Récemment, un site portail africain de données ouvertes appelé openAFRICA géré par une organisation appelée Code for Africa et son propre approvisionnement en eau au Rwanda La fonction de liaison automatique des données de tuiles vectorielles de l'eau, gérée conjointement avec la société publique WASAC, a été implémentée en Python.
Puisqu'il utilise une API appelée CKAN, qui semble être largement utilisée dans les sites de données ouvertes des gouvernements locaux japonais, je pense qu'elle peut être utilisée lorsque vous souhaitez lier automatiquement des données ouvertes telles que des fichiers appartenant à votre organisation via l'API. Alors je veux le partager.
-Vous avez votre propre compte sur une plateforme de données ouvertes utilisant CKAN API --Gestion des données ouvertes sur Github
Tout au long de cet article, lorsque les données ouvertes sur Github sont mises à jour, Github Action sera utilisé pour lier automatiquement les données sur la plateforme via CKAN.
À propos, la page openAFRICA des données ouvertes de la tuile vecteur eau de la Rwanda Water Authority peut être trouvée sur le lien suivant. https://open.africa/dataset/rw-water-vectortiles
De plus, le référentiel Github des tuiles vectorielles de l'eau se trouve sur le lien ci-dessous, et est automatiquement mis à jour vers Github à partir du serveur du bureau public de l'eau chaque semaine. https://github.com/WASAC/vt
Si pipenv n'est pas installé, veuillez d'abord le configurer.
git clone https://github.com/watergis/open-africa-uploader
cd open-africa-uploader
pipenv install
pipenv shell
Tout d'abord, je publierai le code source complet de OpenAfricaUploader.py
dans le référentiel.
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)
Le code source pour appeler OpenAfricaUploader.py
pour télécharger un fichier ressemble à ceci:
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.')
Je vais expliquer un par un.
Ce module a l'URL du site portail de base définie dans le constructeur à l'avance pour le téléchargement vers openAFRICA.
Remplacez l'URL de self.data_portal = 'https: // africaopendata.org'
par l'URL de l'API CKAN utilisée par votre organisation.
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)
L'appel au constructeur ressemble à ceci: Spécifiez la clé API CKAN de votre compte dans args.key
.
uploader = OpanAfricaUploader(args.key)
Créez un package à l'aide de l'API package_create. À ce moment-là, spécifiez ce qui suit dans l'argument.
--name = La chaîne de caractères spécifiée ici sera l'URL du package --title = Titre du package --owner_org = ID de l'organisation cible sur le portail CKAN
Si la création réussit, les informations du package seront renvoyées sous forme de valeur de retour. S'il existe déjà, une erreur se produira, donc j'écris un processus pour obtenir les informations sur le package existant dans le processus d'exception.
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
La façon d'appeler cette fonction est la suivante
uploader.create_package('rw-water-vectortiles','Vector Tiles for rural water supply systems in Rwanda')
Les ressources sont créées avec une fonction appelée resource_create
. Vous pouvez utiliser l'API REST / api / action / resource_create
pour transmettre les données binaires et les informations de fichier à télécharger.
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']))
Cependant, si vous n'utilisez que resource_create
, vous ne pouvez ajouter que des ressources, et le nombre augmentera régulièrement à chaque mise à jour, utilisez donc l'API / api / action / resource_update
pour mettre à jour s'il y a des ressources existantes. Je le ferai.
L'utilisation de «resource_update» est fondamentalement la même que de «resource_create», la seule différence est de savoir s'il y a ou non «resource_id» dans «data».
def resource_update(self, data, path):
self.resource_create(data, path, "/api/action/resource_update")
Une fonction appelée upload_datasets
combine resource_create
et resource_update
d'une manière agréable pour mettre à jour les ressources existantes si elles existent et en créer de nouvelles si elles n'existent pas.
def upload_datasets(self, path, description):
#Séparez le nom du fichier de l'extension
filename = os.path.basename(path)
extension = os.path.splitext(filename)[1][1:].lower()
#Créer des données pour la création de ressources
data = {
'package_id': self.package['id'], #ID du package
'name': filename, #Nom de fichier à mettre à jour
'format': extension, #Format (ici, extension)
'description': description #Description du fichier
}
#S'il existe déjà une ressource dans le package, vérifiez s'il existe une ressource portant le même nom que le nom de fichier à télécharger.
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 s'il n'y a pas de ressource avec le même nom_Appelez créer
self.resource_create(data, path)
else:
#S'il y a une ressource, définissez l'ID dans les données et la ressource_Mise à jour de l'appel
print ('Resource "{}" already exists, it will be overwritten'.format(target_resource['name']))
data['id'] = target_resource['id']
self.resource_update(data, path)
else:
#Ressource si aucune ressource_Appelez créer
self.resource_create(data, path)
La manière d'appeler la fonction upload_datasets
est la suivante.
uploader.upload_datasets(os.path.abspath('../data/rwss.mbtiles'), 'mbtiles format of Mapbox Vector Tiles which was created by tippecanoe.')
Vous pouvez l'appeler depuis la ligne de commande avec upload2openafrica.py
.
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)
Lors de son utilisation, cela ressemble à ce qui suit. Je crée un script shell appelé upload_mbtiles.sh
. Assurez-vous de définir la variable d'environnement sur CKAN_API_KEY
.
#!/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."
Vous pouvez désormais télécharger des données ouvertes à l'aide de l'API CKAN.
Cependant, il est difficile de lier manuellement avec CKAN à chaque fois, je vais donc l'automatiser avec Github Action. Le fichier de workflow ressemble à ceci:
name: openAFRICA upload
on:
push:
branches: [ master ]
#Ici, le flux de travail s'exécute lorsque le dossier de données et ci-dessous sont mis à jour.
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
#Commencez par définir les paramètres initiaux de Pipenv.
run: |
cd scripts
pip install pipenv
pipenv install
- name: upload to openAFRICA
#CKAN in Secrets sur la page Paramètres du référentiel Github_API_Si vous vous inscrivez avec le nom KEY, vous pouvez utiliser les variables d'environnement comme suit.
env:
CKAN_API_KEY: ${{secrets.CKAN_API_KEY}}
#Après cela, j'appellerai le script shell
run: |
cd scripts
./upload_mbtiles.sh
Avec cela seul, une fois le fichier téléchargé sur Github, il peut être automatiquement lié à la plate-forme de données ouvertes. L'image suivante est l'écran lorsque Github Aciton de la Rwanda Water Authority est exécuté.
L'API CKAN est utilisée sur diverses plates-formes open source au pays et à l'étranger. L'API CKAN peut implémenter la liaison de données relativement facilement en utilisant Python. De plus, si les données ouvertes sont gérées sur Github, elles peuvent être liées plus facilement et automatiquement à l'aide de Github Action.
Nous espérons que le module créé pour openAFRICA sera utile pour utiliser les données ouvertes en utilisant d'autres CKAN au Japon et à l'étranger.
Recommended Posts