Verwenden Sie die Curl / JQ-Bibliothek mit Go

Einführung

Es geht um die Umgebungskonstruktion von Go, um json mit der Curl-Bibliothek zu erhalten und json mit der jq-Bibliothek zu analysieren. Es ist möglich, dies nur mit der Standardbibliothek [^ lib] zu tun, aber durch die Verwendung einer Bibliothek typischer Befehle möchte ich die neue Speicherung reduzieren und den Unterschied in der Implementierung zwischen den Sprachen so weit wie möglich reduzieren.

Da jede Bibliothek in der Sprache C bereitgestellt wird, ist es gut, sie direkt zu verwenden, wenn Sie sie in Go verwenden. Der Einfachheit halber verwenden wir jedoch die Wrapper-Bibliothek.

[^ lib]: Holen Sie sich json mit "net / http" und analysieren Sie json mit "encoding / json".

Umgebung

Die Umgebung ist wie folgt.

Die Wrapper-Bibliothek ist wie folgt: Beide sind dünne Wrapper und tun nichts extra.

Aufbau der MSYS2-Umgebung

Installieren Sie Curl- und JQ-Bibliotheken. Ich arbeite am Terminal von MSYS2.

Installation der Curl-Bibliothek und der JQ-Bibliothek

Verwenden Sie Alexpux / MINGW-Pakete für die Installation und erstellen Sie jede Bibliothek mit dem Befehl makepkg (Quelldownload jeder Bibliothek, Patch für MSYS2, Build). Sie können es einfach mit installieren (es wird alles automatisch erledigen).

[^ libcurl]: Mit libcurl, das von pacman installiert wurde, konnten curl_global_init und curl_easy_init aufgrund eines Fehlers beim Aufrufen der Realloc-Funktion nicht ausgeführt werden.

Installation


#Paket aktualisieren
$ pacman -Syuu
#* Wenn die folgende Warnung angezeigt wird, starten Sie das Terminal neu und versuchen Sie es erneut.
#Warnung: terminate MSYS2 without returning to shell and check for updates again
#Warnung: for example close your terminal window instead of calling exit
$ pacman -Syuu

#Installieren Sie Build-bezogene Pakete, die von makepkg verwendet werden
$ pacman -S git base-devel mingw-w64-x86_64-toolchain

# MINGW-Git-Klon-Pakete
$ cd /tmp
$ git clone --depth=1 https://github.com/Alexpux/MINGW-packages.git

#baue jq&Installation
$ cd /tmp/MINGW-packages/
$ cd `ls | grep jq`
# -Installieren Sie abhängige Pakete, die mit der Option s fehlen
$ makepkg -s
#Installation lokaler Pakete
$ pacman -U ./mingw-w64-x86_64-jq-1.5-3-any.pkg.tar.xz
#Klicken Sie hier für die direkte Installation
#$ cp -r pkg/mingw-w64-x86_64-jq/mingw64/* /mingw64/

#Curl bauen&Installation
$ cd /tmp/MINGW-packages/
$ cd `ls | grep curl`
$ makepkg -s
#Wenn Sie die Meldung erhalten, dass der PGP-Schlüssel nicht überprüft werden kann, importieren Sie ihn, da kein öffentlicher Schlüssel vorhanden ist.
# ==>Überprüfen Sie die Signatur der Quelldatei mit gpg...
#     curl-7.52.1.tar.bz2 ...Fehler(Unbekannter öffentlicher Schlüssel 5CC908FDB71E12C2) <-* Kopier das
# ==>Error:Der PGP-Schlüssel konnte nicht verifiziert werden!
$ gpg --recv-keys 5CC908FDB71E12C2
#Erneut ausführen
$ makepkg -s
#Installation lokaler Pakete
$ pacman -U ./mingw-w64-x86_64-curl-7.52.1-1-any.pkg.tar.xz
#Klicken Sie hier für die direkte Installation
#$ cp -r pkg/mingw-w64-x86_64-curl/mingw64/* /mingw64/

Funktionsprüfung (C)

Kompilieren Sie die folgende Quelle und führen Sie sie mit gcc aus. Wenn "ok" ausgegeben wird, ist die Erstellung der Curl-Umgebung erfolgreich. Ich werde jq weglassen, weil es danach in Go verwendet wird.

test_curl.c


//Überprüfen Sie, ob die SSL-Authentifizierung von curl funktioniert
#include <stdio.h>
#include <curl/curl.h>

size_t noop_function(char *buffer, size_t size, size_t nitems, void *instream) {
	return 0;
}

int main() {
	curl_global_init(CURL_GLOBAL_DEFAULT); // NOTE : libcurl-Wenn Sie devel verwenden, können Sie hier gehen

	CURL *curl = curl_easy_init();
	if (!curl) return 1;

	// qiita.SSL-Verbindung zu com
	curl_easy_setopt(curl, CURLOPT_URL, "https://qiita.com");
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
	//Standardmäßig wird die Antwort auf die Standardausgabe ausgegeben, was ärgerlich ist. Drücken Sie sie also zusammen.
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION , noop_function);
	curl_easy_perform(curl);

	//HTTP-Antwort abrufen
	long http_code = 0;
	curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
	if (http_code == 200) printf("ok");

	curl_easy_cleanup(curl);
	return 0;
}

kompilieren&Lauf


$ gcc test_curl.c -I/mingw64/include -L/mingw64/lib -lcurl
$ ./a
ok

Gehen Sie Umweltbau

Dies erfolgt über eine Eingabeaufforderung mit einem Pfad zu gcc (C: \ path \ to \ msys64 \ mingw \ bin \ gcc) auf Go und MSYS2. ** * Bitte passen Sie den Pfad zu MSYS2 entsprechend Ihrer Umgebung an. ** ** **

Installieren Sie die Wrapper-Bibliothek


> @rem curl, mache jq library von Go aus sichtbar
> set CGO_CFLAGS=-I C:\path\to\msys64\mingw64\include
> set CGO_LDFLAGS=-L C:\path\to\msys64\mingw64\lib
> @Installieren Sie rem curl, jq wrapper library
> go get -u github.com/andelf/go-curl
> go get -u github.com/mgood/go-jq
> @rem go get -u github.com/wordijp/go-jq

Dies ist das Ende des Umgebungsbaus.

Versuchen Sie es mit der curl / jq-Bibliothek in Go

** (2017/2/11) Hinzugefügt über die Bequemlichkeit von jq **

Holen Sie sich die Post-Liste von Qiita mit Curl, und schränken Sie die Liste der Poster-IDs und Titel mit jq ein und zeigen Sie sie an. Übrigens können Sie die Liste der Beiträge von Alle Beiträge auf Qiita Home überprüfen.

すべての投稿.png

Der JSON der Beitragsliste, der mit der Qiita API v2 abgerufen werden kann, hat das folgende Format.

Qiita_API_V2_items.json


[
  {
    "rendered_body": "Text(Weggelassen, weil es lang ist)",
    "coediting": false,
    "created_at": "2017-02-09T20:29:56+09:00",
    "group": null,
    "id": "acb70ae51c334aa1ee52",
    "private": false,
    "tags": [
      {
        "name": "C",
        "versions": []
      },
      {
        "name": "Go",
        "versions": []
      },
      {
        "name": "curl",
        "versions": []
      },
      {
        "name": "jq",
        "versions": []
      },
      {
        "name": "msys2",
        "versions": []
      }
    ],
    "title": "Curl in Go/Verwenden Sie die jq-Bibliothek",
    "updated_at": "2017-02-09T21:24:05+09:00",
    "url": "http://qiita.com/wordijp/items/acb70ae51c334aa1ee52",
    "user": {
      "description": "C++ich mag(C++Ich sage nicht, dass ich einen Artikel posten werde)",
      "facebook_id": "",
      "followees_count": 7,
      "followers_count": 9,
      "github_login_name": "wordijp",
      "id": "wordijp",
      "items_count": 33,
      "linkedin_id": "",
      "location": "",
      "name": "",
      "organization": "",
      "permanent_id": 51728,
      "profile_image_url": "https://qiita-image-store.s3.amazonaws.com/0/51728/profile-images/1473692528",
      "twitter_screen_name": "wordijp",
      "website_url": ""
    }
  },
  {
2. Artikel
  }
]

Die jq-Zeichenfolge, die von hier aus nach Poster-ID und Titelgruppe analysiert wird, lautet wie folgt.

Zeichenkette für jq(Poster ID und Titelgruppe)


'.[] | {user_id: .user.id, title: .title}'

Nach dem Parsen sieht es wie folgt aus.

Poster ID und Titelgruppe.json


{
  "user_id": "wordijp",
  "title": "Curl in Go/Verwenden Sie die jq-Bibliothek"
}
{
2. Artikel
}

Übrigens, wenn Sie analysieren, während Sie die Sequenz beibehalten, wird es wie folgt sein: Ich benutze es zum Zeitpunkt der Implementierung nicht, aber ich werde es nur einführen, weil es zufällig ist.

Zeichenkette für jq(Poster-ID und Titelgruppe, Array-Wartung Ver)


'. | [{user_id: .[].user.id, title: .[].title}]'

Nach dem Parsen sieht es wie folgt aus.

Poster-ID und Titelgruppe, Array-Wartung Ver.json


[
  {
    "user_id": "wordijp",
    "title": "Curl in Go/Verwenden Sie die jq-Bibliothek"
  },
  {
2. Artikel
  }
]

Klicken Sie hier für den Go-Quellcode

test_curl_json.go


//Rufen Sie die Qiita API v2 auf und listen Sie die Poster-ID und den Titel des veröffentlichten Artikels auf
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	curl "github.com/andelf/go-curl"
	"sync/atomic"
	jq "github.com/mgood/go-jq" // <del>PR-Fehlerbehebung</del>Fest!
	//jq "github.com/wordijp/go-jq" //Der ursprüngliche Fehler wurde behoben, sodass er nicht mehr benötigt wird
)

type wrdata struct {
	ch     chan []byte //Zur Weitergabe erfasster Daten
	remain int32       //Verbleibende Anzahl der erfassten Daten
	//Zur Synchronisation der Parallelverarbeitung
	perform  chan int
	complete chan int
}

//Führen Sie die cURL-Datenerfassung und die Rückgabewertverarbeitung parallel aus
// NOTE :Ein bisschen schneller als sequentiell
func easyParallelWrite(easy *curl.CURL, fWrite func([]byte)) {

	// write function
	easy.Setopt(curl.OPT_WRITEFUNCTION, func(ptr []byte, userdata interface{}) bool {
		//println("ptr size:", len(ptr))
		wd, ok := userdata.(*wrdata)
		if !ok {
			println("ERROR!")
			return false
		}

		atomic.AddInt32(&wd.remain, 1)
		wd.ch <- ptr
		return true // ok
	})

	// write data
	wd := &wrdata{
		ch:       make(chan []byte, 100),
		remain:   0,
		perform:  make(chan int),
		complete: make(chan int),
	}
	var buf bytes.Buffer
	go func(wd *wrdata) {
		performed := false
	loop:
		for {
			if !performed {
				select {
				case <-wd.perform:
					performed = true
					//Daten wurden bereits erfasst
					if atomic.LoadInt32(&wd.remain) <= 0 {
						break loop
					}
				default:
					// no-op
				}
			}

			data := <-wd.ch
			atomic.AddInt32(&wd.remain, -1)
			//println("Got data size=", len(data))
			buf.Write(data)
			// complete after performed
			if performed && atomic.LoadInt32(&wd.remain) <= 0 {
				break
			}
		}

		//println("recv finished!")
		wd.complete <- 1
	}(wd)
	easy.Setopt(curl.OPT_WRITEDATA, wd)

	easy.Perform()

	//Warten Sie, bis die Datenerfassung abgeschlossen ist
	wd.perform <- 1
	<-wd.complete

	//Gibt das Ergebnis zurück
	fWrite(buf.Bytes())
}

//Hilfsfunktion
//Der Curl-Prozess ist hier zusammengefasst
func curlExec(url string, fWrite func([]byte)) {
	curl.GlobalInit(curl.GLOBAL_DEFAULT)
	defer curl.GlobalCleanup()

	easy := curl.EasyInit()
	defer easy.Cleanup()

	easy.Setopt(curl.OPT_URL, url)
	//easy.Setopt(curl.OPT_SSL_VERIFYPEER, 0) //Während SSL aktiviert
	easyParallelWrite(easy, fWrite)
}

type Item struct {
	UserID string `json:"user_id"`
	Title  string `json:"title"`
}

func main() {
	curlExec("http://qiita.com/api/v2/items", func(buf []byte) {
		j, _ := jq.NewJQ(".[] | {user_id: .user.id, title: .title}")

		j.HandleJson(string(buf))
		for j.Next() {
			item := &Item{}
			valuejson := j.ValueJson()
			json.Unmarshal(([]byte)(valuejson), &item)

			fmt.Println(valuejson)                        // JSON
			fmt.Println(item.UserID + " : " + item.Title) //Struktur
			fmt.Println()
		}
	})
}

Ausführungsergebnis


> go run test_curl_json.go
{"user_id":"kazuma1989","title":"Beachten Sie die Mindestkonfiguration, um Jetty vorerst mit Docker auszuführen"}
kazuma1989 :Beachten Sie die Mindestkonfiguration, um Jetty vorerst mit Docker auszuführen

{"user_id":"ironsand","title":"foo_Beachten Sie, dass wenn Sie BarHoge camelisieren, es zu FooBarhoge wird."}
ironsand : foo_Beachten Sie, dass wenn Sie BarHoge camelisieren, es zu FooBarhoge wird.

{"user_id":"Teach","title":"Flash-Sprung mit ThirdPersonController"}
Teach :Flash-Sprung mit ThirdPersonController
Abkürzung

Ich verwende jq, um die gewünschten Daten aus dem erfassten JSON zu extrahieren. Jq verfügt über eine so leistungsstarke Filterfunktion. Ich denke, es wäre schwierig, dies ohne Verwendung von jq zu implementieren. Jq ist praktisch ..

Außerdem wird die easyParallelWrite-Funktion von goroutine parallelisiert, so dass es etwas kompliziert ist, die gemeinsam genutzte Variable (verbleibend) threadsicher zu verarbeiten, aber ich verwende sie für Leistungszwecke.

Recommended Posts

Verwenden Sie die Curl / JQ-Bibliothek mit Go
Verwenden Sie die Verschlüsselung der Verschlüsselungsbibliothek mit dem Python-Image von Docker
Python mit Go
Verwenden Sie mecab-ipadic-neologd mit igo-python
Verwenden Sie RTX 3090 mit PyTorch
Verwenden Sie ansible mit cygwin
Rufen Sie mit Go mit cgo Ihre eigene C-Sprachbibliothek auf
Verwenden Sie pipdeptree mit virtualenv
[Python] Verwenden Sie JSON mit Python
Verwenden Sie Mock mit Pytest
Verwenden Sie den Indikator mit pd.merge
Verwenden Sie Gentelella mit Django
Verwenden Sie Mecab mit Python 3
Verwenden Sie Tensorboard mit Chainer
Verwenden Sie DynamoDB mit Python
Verwenden Sie pip mit MSYS2
Verwenden Sie Python 3.8 mit Anaconda
Verwenden Sie Copyright mit Spacemacs
Verwenden Sie TypeScript mit Django-Kompressor
Verwenden Sie MySQL mit Django
Verwenden Sie Enum mit SQLAlchemy
Verwenden Sie Tensorboard mit NNabla
Verwenden Sie GPS mit Edison
Verwenden Sie nim mit Jupyter
Verwenden Sie gemeinsam genutzten Speicher mit gemeinsam genutzten Bibliotheken
Verwenden Sie benutzerdefinierte Tags mit PyYAML
Betreiben Sie den Db2-Container mit Go
Verwenden Sie Richtungsdiagramme mit networkx
Verwenden Sie TensorFlow mit Intellij IDEA
Erste Schritte mit Go Assembly
Verwenden Sie die Twitter-API mit Python
Verwenden Sie pip mit Jupyter Notebook
Verwenden Sie DATE_FORMAT mit dem SQLAlchemy-Filter
Vollbit-Suche mit Go
Verwenden Sie TUN / TAP mit Python
Verwenden Sie sqlite3 mit NAO (Pepper)
Stellen Sie mit GO eine Verbindung zu Postgresql her
Verwenden Sie die load_extensions von sqlite mit Pyramid
Verwenden Sie Windows 10-Schriftarten mit WSL
Verwendung von Chainer mit Jetson TK1
Verwenden Sie SSL mit Sellerie + Redis
Verwenden Sie Cython mit Jupyter Notebook
[Go] Verwendung von "... (3 Perioden)"
Verwenden Sie Maxout + CNN mit Pylearn2
Versuchen Sie, Parfüm mit Go zu implementieren
Verwenden Sie WDC-433SU2M2 mit Manjaro Linux
Verwenden Sie OpenBLAS mit numpy, scipy
Verwenden Sie die Unterschall-API mit Python3
Verwenden von Sonicwall NetExtener mit Systemd
Verwenden Sie prefetch_related bequem mit Django
Verwenden Sie einen AWS-Interpreter mit Pycharm
Verwenden von Bokeh mit IPython Notebook
Verwenden Sie Python-ähnliche Bereiche mit Rust
Ich möchte eine externe Bibliothek mit IBM Cloud-Funktionen verwenden