- เรื่องราวการพัฒนาโครงการ LegiNote ตอนที่ 2 - สแตกเทคโนโลยีและเวิร์กเกอร์
- บทความตอนที่สองของเรื่องราวการพัฒนาโครงการ LegiNote ซึ่งจะกล่าวถึงการพัฒนาเวิร์กเกอร์โดยใช้ภาษา Go เนื้อหาครอบคลุมการนำไปใช้ในการรวบรวมและอัปเดตข้อมูล รวมถึงการออกแบบโครงสร้างของโครงการ
โพสต์นี้แปลโดย AI
บทสรุปของโพสต์โดย durumis AI
- ระหว่างการพัฒนาโครงการ LegiNote เราได้ดำเนินการดึงข้อมูลร่างกฎหมายจาก OpenAPI ของสภาผู้แทนราษฎร
- เราใช้ภาษา Go ในการส่งคำขอ HTTP เพื่อดึงข้อมูล และทำการแยกวิเคราะห์ข้อมูล JSON ที่ได้รับออกมาเป็นโครงสร้างข้อมูล
- บทความนี้จะอธิบายขั้นตอนตั้งแต่การขอรับ API Key การส่งคำขอข้อมูล ไปจนถึงการแยกวิเคราะห์ข้อมูล พร้อมทั้งสำรวจแนวทางการปรับปรุงในอนาคต
สวัสดีครับ ผม StatPan
กำลังเขียนเกี่ยวกับการพัฒนา LegiNote ซึ่งเป็นโปรเจกต์ข้างเคียง
สำหรับตอนก่อนหน้า โปรดดูลิงก์ด้านล่างนี้
Worker ตัวที่ 1 worker-bill
ชื่อ bill ดูเหมือนชื่อเพื่อนชาวต่างชาติที่คุ้นเคยใช่มั้ยครับ ผมได้รับแรงบันดาลใจจากความหมายของคำนี้
ก่อนหน้านี้ ผมเคยค้นหาคำศัพท์ภาษาอังกฤษที่เกี่ยวข้องกับโดเมนของสภาเพื่อหาชื่อตัวแปรและชื่อที่เก็บที่ดี ซึ่งผมนำสิ่งที่ค้นพบมาประยุกต์ใช้
ความหมายของคำว่า bill
สเปก OpenAPI ของแหล่งข้อมูลที่ Worker จะรวบรวมมีดังนี้
พารามิเตอร์อินพุต
พารามิเตอร์อินพุตของ API การพิจารณาและดำเนินการร่างกฎหมาย
พารามิเตอร์เอาต์พุต
พารามิเตอร์อินพุตของ API การพิจารณาและดำเนินการร่างกฎหมาย
ดูเหมือนว่าจะให้ข้อมูลค่อนข้างเยอะและสามารถให้บริการข้อมูลรายละเอียดได้มากทีเดียว
สิ่งที่ต้องเตรียมสำหรับ Http Request
ก่อนอื่น มาดูกันว่าเราต้องเตรียมอะไรบ้างสำหรับการส่งคำขอ Http Request ตามพารามิเตอร์อินพุตข้างต้น
URL, วิธีการส่งคำขอ Http request(แม้ว่าจะไม่ได้ระบุไว้ในที่นี้ แต่เป็น Get นะครับ Post ใช้ไม่ได้ㅠ), KEY, Type, pIndex, pSize ครับ
สำหรับ KEY นั้น คล้ายกับ OpenAPI อื่นๆ ที่คุณต้องขอรับ API Key แยกต่างหาก
เนื่องจากนี่คือเรื่องราวการพัฒนา ดังนั้นผมจึงต้องการแนบลิงก์อ้างอิงไว้ด้วย แต่เนื่องจากยังไม่ค่อยมีคนรู้จักเท่าไหร่ จึงไม่มีบทความเกี่ยวกับวิธีขอรับ API Key ใน Google เลย... เอาเป็นว่าตอนนี้ผมจะอธิบายคร่าวๆ พร้อมรูปภาพนะครับ...
หน้าแรก
คลิกที่ปุ่ม My Page บนหน้าแรก
หน้า My Page
หน้าจอการขอรับ API Key
ในส่วนของวัตถุประสงค์การใช้งานหรือเนื้อหา ในกรณีของผม ผมเขียนสั้นๆ ว่าเพื่อการแข่งขันข้อมูลสาธารณะครับ คุณไม่ต้องกังวลกับการกรอกข้อมูลส่วนนี้มากนัก ถ้าไม่ใช่เหตุผลที่ไม่ดี(หรือไม่เหมาะสม) สัก 1-2 บรรทัด ก็ได้รับอนุมัติแล้วล่ะครับ
API Key ที่ได้รับจะใช้เป็น KEY ในคำอธิบาย HTTP ด้านบน
ลองส่งคำขอไปที่ URL นี้ดูครับ (หวังว่าในการอัปเดตครั้งถัดไป จะมีการระบุเมธอดด้วย)
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") // 이건 왜 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)
```
ผมสามารถทดสอบการทำงานเบื้องต้นได้ด้วยโค้ดข้างต้น
ขอแนะนำเคล็ดลับเล็กน้อย คุณต้องเพิ่ม Header ด้วยนะครับ ถ้าคุณอยากใช้ API นี้ได้อย่างราบรื่น (ขู่เบาๆ)
จากนั้น กรอกพารามิเตอร์ที่จำเป็นลงใน URL ของ Get
ค่าของ pIndex และ pSize ระบุว่าให้ใช้ integer แต่จริงๆ แล้วคุณใช้ string ก็ได้นะครับ (งงมาก)
สามารถใช้รูปแบบ xml ได้ด้วย แต่ผมเลือกใช้ Json
ผลลัพธ์
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?...
จะได้ผลลัพธ์ตามที่แสดงด้านบน
ผมนิยามโครงสร้าง struct ทั้งหมดเพื่อควบคุมวัตถุนั้นๆ โดยตรง ซึ่งใช้เวลาในการดีบักค่อนข้างเยอะเหมือนกัน
เนื่องจากข้อจำกัดจำนวนอักขระ คงต้องมาอธิบายเรื่องการ Unmarshal ค่าเหล่านี้เป็น struct ในตอนถัดไป
แค่ Request เดียวก็กินเนื้อที่ไปเยอะแล้วในบทความนี้ แน่นอนว่าการใช้ OpenAPI นี้ต้องใช้เวลาในการเรียนรู้การใช้งานและโครงสร้าง struct ค่อนข้างมาก แต่ก็ต้องหาทางให้คนอื่นๆ ไม่ต้องเจอกับความทุกข์ทรมานแบบเดียวกัน
สำหรับใครที่พบว่าคำขอข้างต้นไม่ทำงานตามที่ควรจะเป็นหรือไม่พอใจกับโค้ดแปลกๆ ของผม ก็ขอให้ช่วยเตรียมบุหรี่มาด้วยนะครับ