- Historia rozwoju projektu LegiNote 2 - stos technologiczny i worker
- Druga część historii rozwoju projektu LegiNote, skupiająca się na opracowaniu workera w języku Go. Artykuł omawia implementację logiki zbierania i aktualizacji danych oraz sposób organizacji projektu.
Tekst przetłumaczony przez AI.
Podsumowanie posta wygenerowane przez AI durumis
- Podczas rozwoju projektu LegiNote podjęliśmy się zadania pobierania informacji o projektach ustaw z otwartego API Parlamentu.
- Użyliśmy języka Go do wysyłania żądań HTTP w celu pobrania danych i sparsowania otrzymanych danych JSON do struktur.
- Opisujemy proces od uzyskania klucza API, przez wysyłanie żądań, po parsowanie danych, jednocześnie poszukując kierunków przyszłych ulepszeń.
Dzień dobry, jestem StatPan.
Piszę o rozwoju projektu pobocnego LegiNote.
Aby zapoznać się z poprzednią częścią, proszę odwiedzić następujący link:
Pracownik nr 1 worker-bill
Nazwa "bill" brzmi jak imię zagranicznego przyjaciela, prawda? Inspirację do niej zaczerpnąłem z następującego znaczenia słowa:
Wcześniej, szukając odpowiednich nazw zmiennych i repozytoriów związanych z domeną parlamentarną, przeglądałem różne angielskie słowa. To właśnie tam znalazłem inspirację, którą teraz wykorzystuję.
znaczenie słowa bill
Specyfikacja OpenAPI, z którego Worker będzie pobierał dane, wygląda następująco:
Parametry wejściowe
Parametry wejściowe API do oceny i przetwarzania projektów ustaw
Parametry wyjściowe
Parametry wejściowe API do oceny i przetwarzania projektów ustaw
Wygląda na to, że dostarcza on sporo danych i może udostępniać dość szczegółowe informacje.
Wymagane elementy żądania HTTP
Przeanalizujmy, co jest potrzebne do wysłania żądania HTTP z powyższymi parametrami wejściowymi:
Adres URL, metoda żądania HTTP(chociaż nie jest to tutaj podane, Get jest używana, a Post nie działa), KLUCZ, Typ, pIndex, pSize – to właśnie te wartości są potrzebne.
W przypadku klucza, podobnie jak w innych interfejsach API, należy uzyskać osobny klucz uwierzytelniający.
Skoro piszę o rozwoju, chciałem dodać link do źródła, ale… ponieważ API jest jeszcze mało popularne, nie znalazłem w Google żadnego artykułu opisującego sposób uzyskania klucza uwierzytelniającego. Na razie, przedstawię to graficznie:
Ekran główny
Na stronie głównej kliknij przycisk "Moja strona".
Moja strona
Ekran generowania klucza API
W moim przypadku, w polu "Cel wykorzystania" lub "Treść" wpisałem krótko: "do udziału w konkursie danych publicznych". Nie martwcie się zbytnio o treść tego pola. Jeśli nie zawiera ono niczego nieprzyzwoitego, myślę, że zatwierdzenie nastąpi od razu po wpisaniu 1-2 zdań.
W ten sposób otrzymacie klucz, który jest niezbędny w opisie HTTP – KEY.
Wyślijmy żądanie do powyższego adresu URL (mam nadzieję, że w następnej aktualizacji zostanie uwzględniona także metoda).
go```go package main import ( "encoding/json" "fmt" "io" "log" "net/http" "net/url" ) func procErr(e error, msg string) { if e != nil { log.Fatal(e, msg) } } func main() { rawUrl := "https://open.assembly.go.kr/portal/openapi/TVBPMBILL11" parsedUrl, err := url.Parse(rawUrl) procErr(err, "err after parsedUrl") params := url.Values{} KEY := "your_key" //change this procErr(err, "err after req, 27") req.Header.Add("Content-Type", "application/json") req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36") params.Add("KEY", KEY) params.Add("Type", "json") // JSON 좋.아 params.Add("pIndex", "1") // this is why it is integer, string params.Add("pSize", "1") client := &http.Client{} reqURL := fmt.Sprintf("%s?%s", rawUrl, params.Encode()) req, err := http.NewRequest(http.MethodGet, reqURL, nil) res, err := client.Do(req) procErr(err, "err, after client do") defer res.Body.Close() var jsonMap any response, err := io.ReadAll(res.Body) procErr(err, "err after read response") err = json.Unmarshal(response, &jsonMap) procErr(err, "err after json unmarshal") fmt.Println(jsonMap)
```
Za pomocą powyższego kodu udało mi się sprawdzić poprawność działania.
Mała wskazówka: należy koniecznie dodać nagłówek, jeśli chcecie, aby to API działało bezproblemowo (to żart).
Następnie uzupełnijmy parametry wymagane w adresie URL żądania Get.
Wartości pIndex i pSize powinny być typu integer, ale można je podać jako string i nadal będą działać (nie rozumiem tego).
Można również użyć formatu XML w polu Type, ale ja wybrałem JSON.
Wynik
map[TVBPMBILL11:[map[head:[map[list_total_count:103305] map[RESULT:map[CODE:INFO-000 MESSAGE:정상 처리되었습니다.]]]] map[row:[map[AGE:22 BILL_ID:PRC_T2U4C0A8B2Z0A1Y3Y5G2H0F0G5E4F4 BILL_NAME:정치자금법 일부개정법률안 BILL_NO:2203179 CMT_PRESENT_DT: CMT_PROC_DT: CMT_PROC_RESULT_CD: COMMITTEE_DT: COMMITTEE_PROC_DT: CURR_COMMITTEE: CURR_COMMITTEE_ID: LAW_PRESENT_DT: LAW_PROC_DT: LAW_PROC_RESULT_CD: LAW_SUBMIT_DT: LINK_URL:https://likms.assembly.go.kr/bill/billDetail.do?billId=PRC_T2U4C0A8B2Z0A1Y3Y5G2H0F0G5E4F4 PROC_DT: PROC_RESULT_CD: PROPOSER:고동진의원 등 10인 PROPOSER_KIND:의원 PROPOSE_DT:2024-08-23 RST_MONA_CD:HS39431V RST_PROPOSER:고동진] map[AGE:22 BILL_ID:PRC_O2M4M0L8L2T0R1S3Q5R1P4Q0Y2W2X6 BILL_NAME:정당법 일부개정법률안 BILL_NO:2203178 CMT_PRESENT_DT: CMT_PROC_DT: CMT_PROC_RESULT_CD: COMMITTEE_DT: COMMITTEE_PROC_DT: CURR_COMMITTEE: CURR_COMMITTEE_ID: LAW_PRESENT_DT: LAW_PROC_DT: LAW_PROC_RESULT_CD: LAW_SUBMIT_DT: LINK_URL:https://likms.assembly.go.kr/bill/billDetail.do?...
Otrzymujemy taki wynik.
Aby móc bezpośrednio sterować tym obiektem, zdefiniowałem wszystkie struktury i pobierałem wartości. To z kolei wiązało się z wieloma sesjami debugowania.
Ze względu na ograniczenie liczby znaków, opis parsowania tego wyniku do struktury będzie musiał poczekać na kolejną część.
Jedno żądanie zajęło mi sporo miejsca w tym wpisie z dziennika rozwoju. Oczywiście, biorąc pod uwagę specyfikę tego interfejsu API, sporo czasu poświęciłem na jego wykorzystanie i przygotowanie struktury danych. Trzeba będzie znaleźć sposób, aby inni nie musieli przechodzić przez te same trudności.
Jeśli napotkacie jakieś problemy z powyższym żądaniem lub mój kod Was irytuje, to proszę o pomoc (i może papierosa).