Il s'agit de la construction de l'environnement à partir de Go pour obtenir json avec la bibliothèque curl et analyser json avec la bibliothèque jq. Il est possible de le faire uniquement avec la bibliothèque standard [^ lib], mais en utilisant une bibliothèque de commandes typiques, je voudrais réduire la nouvelle mémorisation et réduire autant que possible la différence d'implémentation entre les langages.
Comme chaque bibliothèque est fournie en langage C, il est bon de l'utiliser directement lors de son utilisation dans Go, mais pour plus de commodité, nous utiliserons la bibliothèque wrapper.
[^ lib]: Récupère json avec "net / http" et analyse json avec "encoding / json"
L'environnement est le suivant.
Les bibliothèques de wrapper sont les suivantes, les deux sont des wrappers légers et ne font rien de plus.
Installez les bibliothèques curl et jq. Je travaille sur le terminal de MSYS2.
Utilisez Alexpux / MINGW-packages pour l'installation, et créez chaque bibliothèque avec la commande makepkg (téléchargement source de chaque bibliothèque, correctif pour MSYS2, build). Vous pouvez facilement l'installer avec (il fera tout automatiquement).
[^ libcurl]: Avec libcurl installé par pacman, curl_global_init et curl_easy_init n'ont pas pu être exécutés en raison d'une erreur lors de l'appel de la fonction realloc.
Installation
#Mettre à jour le package
$ pacman -Syuu
#* Si l'avertissement suivant apparaît, redémarrez le terminal et réessayez.
#avertissement: terminate MSYS2 without returning to shell and check for updates again
#avertissement: for example close your terminal window instead of calling exit
$ pacman -Syuu
#Installer les packages liés à la construction utilisés par makepkg
$ pacman -S git base-devel mingw-w64-x86_64-toolchain
# MINGW-paquets git clone
$ cd /tmp
$ git clone --depth=1 https://github.com/Alexpux/MINGW-packages.git
#construire jq&Installation
$ cd /tmp/MINGW-packages/
$ cd `ls | grep jq`
# -Installez les packages dépendants manquants avec l'option s
$ makepkg -s
#Installation de packages locaux
$ pacman -U ./mingw-w64-x86_64-jq-1.5-3-any.pkg.tar.xz
#Cliquez ici pour une installation directe
#$ cp -r pkg/mingw-w64-x86_64-jq/mingw64/* /mingw64/
#construire curl&Installation
$ cd /tmp/MINGW-packages/
$ cd `ls | grep curl`
$ makepkg -s
#Si vous recevez un message indiquant que la clé PGP ne peut pas être vérifiée, importez-la car il n'y a pas de clé publique.
# ==>Valider la signature du fichier source avec gpg...
# curl-7.52.1.tar.bz2 ...Échec(Clé publique inconnue 5CC908FDB71E12C2) <-* Copiez ceci
# ==>Erreur:La clé PGP n'a pas pu être vérifiée!
$ gpg --recv-keys 5CC908FDB71E12C2
#Ré-exécuter
$ makepkg -s
#Installation de packages locaux
$ pacman -U ./mingw-w64-x86_64-curl-7.52.1-1-any.pkg.tar.xz
#Cliquez ici pour une installation directe
#$ cp -r pkg/mingw-w64-x86_64-curl/mingw64/* /mingw64/
Compilez et exécutez la source suivante avec gcc, et si "ok" est affiché, la construction de l'environnement curl est réussie. J'omettrai jq car il sera utilisé dans Go après cela.
test_curl.c
//Vérifiez si l'authentification SSL de curl fonctionne
#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-Si vous utilisez devel, vous pouvez aller ici
CURL *curl = curl_easy_init();
if (!curl) return 1;
// qiita.Connexion SSL à com
curl_easy_setopt(curl, CURLOPT_URL, "https://qiita.com");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
//Par défaut, la réponse est sortie sur la sortie standard, ce qui est ennuyeux, alors serrez-la.
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION , noop_function);
curl_easy_perform(curl);
//Obtenir une réponse HTTP
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;
}
compiler&Courir
$ gcc test_curl.c -I/mingw64/include -L/mingw64/lib -lcurl
$ ./a
ok
Cela se fait à partir d'une invite de commande qui a un chemin vers gcc (C: \ chemin \ vers \ msys64 \ mingw \ bin \ gcc) sur Go et MSYS2. ** * Veuillez faire correspondre le chemin vers MSYS2 en fonction de votre environnement. ** **
Installer la bibliothèque d'encapsuleurs
> @rem curl, rendre la bibliothèque jq visible depuis Go
> set CGO_CFLAGS=-I C:\path\to\msys64\mingw64\include
> set CGO_LDFLAGS=-L C:\path\to\msys64\mingw64\lib
> @Installer rem curl, bibliothèque de wrapper jq
> 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
C'est la fin de la construction de l'environnement.
** (2017/2/11) Ajout de la commodité de jq **
Obtenez la liste des publications de qiita avec curl, et affinez la liste des ID et des titres des affiches avec jq et affichez-la. En passant, vous pouvez consulter la liste des messages de Tous les messages sur Qiita Home.
Le JSON de la liste d'articles pouvant être obtenue avec l'API Qiita v2 a le format suivant.
Qiita_API_V2_items.json
[
{
"rendered_body": "Texte(Omis parce que c'est long)",
"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 en Go/Utiliser la bibliothèque jq",
"updated_at": "2017-02-09T21:24:05+09:00",
"url": "http://qiita.com/wordijp/items/acb70ae51c334aa1ee52",
"user": {
"description": "C++J'aime(C++Je ne dis pas que je publierai un article)",
"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": ""
}
},
{
2e article
}
]
La chaîne jq qui analyse d'ici à l'identifiant de l'affiche et au groupe de titres est la suivante.
Chaîne de caractères pour jq(Identifiant de l'affiche et groupe de titres)
'.[] | {user_id: .user.id, title: .title}'
Après l'analyse, ce sera comme suit.
Identifiant de l'affiche et groupe de titres.json
{
"user_id": "wordijp",
"title": "Curl en Go/Utiliser la bibliothèque jq"
}
{
2e article
}
Au fait, lors de l'analyse syntaxique tout en conservant la séquence, ce sera comme suit, Je ne l'utilise pas au moment de la mise en œuvre, mais je ne le présenterai que parce que c'est accessoire.
Chaîne de caractères pour jq(ID de l'affiche et groupe de titres, maintenance du tableau Ver)
'. | [{user_id: .[].user.id, title: .[].title}]'
Après l'analyse, ce sera comme suit.
ID de l'affiche et groupe de titres, maintenance du tableau Ver.json
[
{
"user_id": "wordijp",
"title": "Curl en Go/Utiliser la bibliothèque jq"
},
{
2e article
}
]
Cliquez ici pour le code source de Go
test_curl_json.go
//Appelez l'API Qiita v2 et indiquez l'ID de l'affiche et le titre de l'article publié
package main
import (
"bytes"
"encoding/json"
"fmt"
curl "github.com/andelf/go-curl"
"sync/atomic"
jq "github.com/mgood/go-jq" // <del>Correction d'un bug PR</del>fixé!
//jq "github.com/wordijp/go-jq" //Le bogue d'origine a été corrigé, il n'est donc plus nécessaire
)
type wrdata struct {
ch chan []byte //Pour la propagation des données acquises
remain int32 //Nombre restant de données acquises
//Pour la synchronisation du traitement parallèle
perform chan int
complete chan int
}
//Exécuter l'acquisition de données cURL et le traitement des valeurs de retour en parallèle
// NOTE :Un peu plus rapide que séquentiel
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
//Les données ont déjà été acquises
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()
//Attendez la fin de l'acquisition des données
wd.perform <- 1
<-wd.complete
//Renvoie le résultat
fWrite(buf.Bytes())
}
//Fonction d'assistance
//Le processus de curl est résumé ici
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) //Activé pendant SSL
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) //Structure
fmt.Println()
}
})
}
Résultat d'exécution
> go run test_curl_json.go
{"user_id":"kazuma1989","title":"Notez la configuration minimale pour exécuter Jetty avec Docker pour le moment"}
kazuma1989 :Notez la configuration minimale pour exécuter Jetty avec Docker pour le moment
{"user_id":"ironsand","title":"foo_Notez que si vous camélisez BarHoge, il deviendra FooBarhoge."}
ironsand : foo_Notez que si vous camélisez BarHoge, il deviendra FooBarhoge.
{"user_id":"Teach","title":"Flash jump avec ThirdPersonController"}
Teach :Flash jump avec ThirdPersonController
Abréviation
J'utilise jq pour extraire les données que je veux du JSON acquis, jq a une fonction de filtrage si puissante, je pense qu'il serait difficile de l'implémenter sans utiliser jq, jq est pratique ..
De plus, la fonction easyParallelWrite est parallélisée par goroutine, il est donc un peu compliqué de traiter la variable partagée (reste) de manière thread-safe, mais elle est utilisée à des fins de performance.
Recommended Posts