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".
Die Umgebung ist wie folgt.
Die Wrapper-Bibliothek ist wie folgt: Beide sind dünne Wrapper und tun nichts extra.
Installieren Sie Curl- und JQ-Bibliotheken. Ich arbeite am Terminal von MSYS2.
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/
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
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.
** (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.
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