В качестве части рекомендаций для Neo4j, которые я представил несколько раз за последний год, у меня есть набор сценариев, которые загружают некоторые данные из API meetup.com .
Все они написаны на Python, но я подумал, что было бы забавно посмотреть, как они будут выглядеть в Go. Моя конечная цель — попытаться распараллелить вызовы API.
Это версия скрипта на Python:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
import requests import os import json key = os.environ[ 'MEETUP_API_KEY' ] lat = "51.5072" lon = "0.1275" seed_topic = "nosql" uri = "https://api.meetup.com/2/groups?⊤ic={0}⪫={1}&lon={2}&key={3}" .format(seed_topic, lat, lon, key) r = requests.get(uri) all_topics = [topic[ "urlkey" ] for result in r.json()[ "results" ] for topic in result[ "topics" ]] for topic in all_topics: print topic |
запросы на импорт импорт или импорт json key = os.environ [‘MEETUP_API_KEY’] lat = «51.5072» lon = «0.1275» seed_topic = «nosql» uri = «https://api.meetup.com/2/groups?&topic= {0} & lat = {1} & lon = {2} & key = {3} ”. Format (seed_topic, lat, lon, key) r = arguments.get (uri) all_topics = [topic [« urlkey »] для результата в r.json () [«results»] для темы в результате [«themes»]] для темы в all_topics: распечатать тему
Мы используем библиотеку запросов, чтобы отправить запрос API-интерфейсу Meetup, чтобы получить группы с темой nosql в районе Лондона. Затем мы анализируем ответ и распечатываем темы.
Теперь сделать то же самое в Go! Первый бит сценария практически идентичен:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import ( "fmt" "os" "net/http" "log" "time" ) func handleError(err error) { if err != nil { fmt.Println(err) log.Fatal(err) } } func main() { var httpClient = &http.Client{Timeout: 10 * time.Second} seedTopic := "nosql" lat := "51.5072" lon := "0.1275" key := os.Getenv( "MEETUP_API_KEY" ) uri := fmt.Sprintf( "https://api.meetup.com/2/groups?⊤ic=%s⪫=%s&lon=%s&key=%s" , seedTopic, lat, lon, key) response, err := httpClient.Get(uri) handleError(err) defer response.Body.Close() fmt.Println(response) } |
import («fmt», «os», «net / http», «log», «время») func handleError (ошибка err) {if err! = nil {fmt.Println (err) log.Fatal (err)}} func main ( ) {var httpClient = & http.Client {Timeout: 10 * time.Second} seedTopic: = «nosql» lat: = «51.5072» lon: = «0.1275» ключ: = os.Getenv («MEETUP_API_KEY») uri: = fmt Ответ .Sprintf («https://api.meetup.com/2/groups?&topic=%s&lat=%s&lon=%s&key=%s», seedTopic, lat, lon, key), err: = httpClient.Get ( uri) handleError (err) отложить ответ. Body.Close () fmt.Println (response)}
Если мы запустим это, мы увидим вывод:
1
2
3
|
$ go cmd /blog/main .go &{200 OK 200 HTTP /2 .0 2 0 map[X-Meetup-Request-Id:[2d3be3c7-a393-4127-b7aa-076f150499e6] X-Ratelimit-Reset:[10] Cf-Ray:[324093a73f1135d2-LHR] X-Oauth-Scopes:[basic] Etag:[ "35a941c5ea3df9df4204d8a4a2d60150" ] Server:[cloudflare-nginx] Set-Cookie:[__cfduid=d54db475299a62af4bb963039787e2e3d1484894864; expires=Sat, 20-Jan-18 06:47:44 GMT; path=/; domain=.meetup.com; HttpOnly] X-Meetup-Server:[api7] X-Ratelimit-Limit:[30] X-Ratelimit-Remaining:[29] X-Accepted-Oauth-Scopes:[basic] Vary:[Accept-Encoding,User-Agent,Accept-Language] Date:[Fri, 20 Jan 2017 06:47:45 GMT] Content-Type:[application /json ;charset=utf-8]] 0xc420442260 -1 [] false true map[] 0xc4200d01e0 0xc4202b2420} |
$ go cmd / blog / main.go & {200 OK 200 HTTP / 2.0 2 0 map [X-Meetup-Request-Id: [2d3be3c7-a393-4127-b7aa-076f150499e6] X-Ratelimit-Reset: [10] Cf -Ray: [324093a73f1135d2-LHR] X-Oauth-Области применения: [базовый] Etag: [«35a941c5ea3df9df4204d8a4a2d60150»] Сервер: [cloudflare-nginx] Набор-cookie: [__ cfduid = d54d3046464499499299599175199199199199199299399399299299 истекает = суббота, 20 января-18 06:47:44 по Гринвичу; Путь = /; домен = .meetup.com; HttpOnly] X-Meetup-Server: [api7] X-Ratelimit-Limit: [30] X-Ratelimit-Remaining: [29] X-Accepted-Oauth-Scopes: [базовый] Варьируется: [Accept-Encoding, User-Agent , Accept-Language] Дата: [Пт, 20 января 2017 г. 06:47:45 GMT] Тип содержимого: [application / json; charset = utf-8]] 0xc420442260 -1 [] false true map [] 0xc4200d01e0 0xc4202b2420}
Все идет нормально. Теперь нам нужно разобрать ответ, который возвращается.
В большинстве примеров, с которыми я сталкивался, предлагается создать структуру со всеми полями, которые вы хотите извлечь из документа JSON, но для такого простого сценария это кажется слишком сложным.
Вместо этого мы можем просто создать карты (string -> interface {}) и затем применить преобразования типов, где это уместно. Я получил следующий код для извлечения тем:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
import "encoding/json" var target map[string] interface {} decoder := json.NewDecoder(response.Body) decoder.Decode(⌖) for _, rawGroup := range target[ "results" ].([] interface {}) { group := rawGroup.(map[string] interface {}) for _, rawTopic := range group[ "topics" ].([] interface {}) { topic := rawTopic.(map[string] interface {}) fmt.Println(topic[ "urlkey" ]) } } |
импортировать «кодирование / json» var target map [string] interface {} decoder: = json.NewDecoder (response.Body) decoder.Decode (& target) для _, rawGroup: = range target [«results»]. ([] интерфейс {}) {group: = rawGroup. (map [string] interface {}) для _, rawTopic: = диапазонная группа [«themes»]. ([] interface {}) {topic: = rawTopic. (map [string] interface {}) fmt.Println (topic [“urlkey”])}}
Это более многословно, чем версия Python, потому что мы должны явно печатать каждую вещь, которую мы берем с карты на каждом этапе, но это не так уж плохо. Это полный скрипт:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
package main import ( "fmt" "os" "net/http" "log" "time" "encoding/json" ) func handleError(err error) { if err != nil { fmt.Println(err) log.Fatal(err) } } func main() { var httpClient = &http.Client{Timeout: 10 * time.Second} seedTopic := "nosql" lat := "51.5072" lon := "0.1275" key := os.Getenv( "MEETUP_API_KEY" ) uri := fmt.Sprintf( "https://api.meetup.com/2/groups?⊤ic=%s⪫=%s&lon=%s&key=%s" , seedTopic, lat, lon, key) response, err := httpClient.Get(uri) handleError(err) defer response.Body.Close() var target map[string] interface {} decoder := json.NewDecoder(response.Body) decoder.Decode(⌖) for _, rawGroup := range target[ "results" ].([] interface {}) { group := rawGroup.(map[string] interface {}) for _, rawTopic := range group[ "topics" ].([] interface {}) { topic := rawTopic.(map[string] interface {}) fmt.Println(topic[ "urlkey" ]) } } } |
основной импорт пакета («fmt», «os», «net / http», «log», «time», «encoding / json») func handleError (ошибка err) {if err! = nil {fmt.Println (err) log.Fatal ( err)}} func main () {var httpClient = & http.Client {Timeout: 10 * time.Second} seedTopic: = «nosql» lat: = «51.5072» lon: = «0.1275» ключ: = os.Getenv (« MEETUP_API_KEY ») uri: = fmt.Sprintf (« https://api.meetup.com/2/groups?&topic=%s&lat=%s&lon=%s&key=%s », seedTopic, lat, lon, key) ответ, err: = httpClient.Get (uri) handleError (err) отложить response.Body.Close () var map map [string] interface {} decoder: = json.NewDecoder (response.Body) decoder.Decode (& target) для _, rawGroup: = целевой диапазон [«результаты»]. ([] interface {}) {group: = rawGroup. (map [string] interface {}) для _, rawTopic: = диапазонная группа [«themes»]. ([] interface {}) {topic: = rawTopic. (map [string] interface {}) fmt.Println (topic [“urlkey”])}}}
Как только я получу эти темы, следующий шаг — сделать больше вызовов API, чтобы получить группы для этих тем.
Я хочу выполнять эти вызовы API параллельно, не допуская превышения ограничений по скорости для API, и думаю, что я могу использовать для этого процедуры go, каналы и таймеры. Но это для другого поста!
Ссылка: | Go vs Python: анализ ответа JSON от HTTP API от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |