Als offene Daten mithilfe der CKAN-API in Python hochladen und automatisch mit Github-Aktionen verknüpfen

Inhaltsverzeichnis

  1. Zusammenfassung
  2. [Voraussetzungen](# Voraussetzungen)
  3. [Daten-Upload-Mechanismus](# Daten-Upload-Mechanismus)
  4. [Automatisierung der Datenverknüpfung](#Automatisierung der Datenverknüpfung)
  5. Zusammenfassung

Überblick

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.

Voraussetzungen

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

image.png

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

image.png

Mechanismus zum Hochladen von Daten

Laden Sie das Repository herunter und installieren Sie es

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

Mechanismus des Datei-Uploads mit der CKAN-API

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.

Konstrukteur

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)

Paket erstellen

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 erstellen und aktualisieren

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

Machen Sie die Quelle des Uploads über die Befehlszeile aufrufbar

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.

Automatisierung der Datenverknüpfung

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.

image.png

Zusammenfassung

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

Als offene Daten mithilfe der CKAN-API in Python hochladen und automatisch mit Github-Aktionen verknüpfen
Holen Sie sich Youtube-Daten in Python mithilfe der Youtube-Daten-API
So senden Sie automatisch E-Mails mit Anhängen mithilfe der Google Mail-API in Python
Laden Sie eine JPG-Datei mit der Google Drive-API in Python hoch
Holen Sie sich LEAD-Daten mit der REST-API von Marketo in Python
Spielen Sie mit der YouTube Data API v3 mit dem Google API Python Client
Öffnen Sie UTF-8 mit Stückliste in Python
Holen Sie sich mit Python zusätzliche Daten zu LDAP
Versuchen Sie es mit der Wunderlist-API in Python
Erstellen Sie automatisch eine Python-API-Dokumentation mit Sphinx
Versuchen Sie, die Kraken-API mit Python zu verwenden
Holen Sie sich Lebensmitteldaten mit Amazon API (Python)
Versuchen Sie, mit Binärdaten in Python zu arbeiten
Tweet mit der Twitter-API in Python
Holen Sie sich Google Fit API-Daten in Python
Erstellen einer Google-Tabelle mit der Python / Google Data-API
Konvertieren Sie CSV- und TsV-Daten in eine Matrix mit Python als Beispiel für MovieLens
Überprüfen Sie Python-Skripte automatisch mit GitHub + Travis-CI + Pycodestyle
[Python] Holen Sie sich alle Kommentare mit Youtube Data Api
Versuchen Sie es mit der BitFlyer Ligntning API in Python
Holen Sie sich die Bild-URL mithilfe der Flickr-API in Python
Holen Sie sich Aktienkursdaten mit Quandl API [Python]
Lassen Sie uns Emotionen mithilfe der Emotions-API in Python beurteilen
Letzte Ranglistenerstellung mit der Qiita-API mit Python
Anonymer Upload von Bildern mit der Imgur-API (mit Python)
[WP REST API v2] Laden Sie Bilder mit Python hoch
Bereiten Sie einen Pseudo-API-Server mit GitHub-Aktionen vor
Versuchen Sie, die ChatWork-API und die Qiita-API in Python zu verwenden
Versuchen Sie, die DropBox Core-API mit Python zu verwenden
Registrieren Sie gemeinsam Daten im Firestore mithilfe der CSV-Datei in Python
Grundeinstellungen bei Verwendung der foursquare-API mit Python
Spielen mit der benutzerlokalen API für künstliche Intelligenz in Python
Verwenden Sie Cursur, das in Python automatisch mit sqlite3 geschlossen wird
[Python] Abrufen von Insight-Daten mithilfe der Google My Business-API
OpenVINO verwendet die Inference Engine Python API in einer PC-Umgebung
Verwenden wir die offenen Daten von "Mamebus" in Python
Verarbeiten Sie CSV-Daten mit Python (Zählverarbeitung mit Pandas)
Verwenden Sie die Such-API der National Parliament Library in Python