성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
[공진영] 안녕하세요 좋은글 감사합니다. 현재 제가 wpf로 관제 모...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>공공 데이터 포털에서 버스 노선 및 위치 정보 조회 API 사용법</h1> <p> 이를 위해서는 우선 다음의 사이트에 회원 가입을 해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 공공데이터 포털 ; <a target='tab' href='https://www.data.go.kr'>https://www.data.go.kr</a> </pre> <br /> 그런 다음 OpenAPI에 대한 사용 신청을 해야 하는데, 약간의 선행 지식이 필요합니다.<br /> <br /> 대개의 경우, 버스라는 것은 "번호"를 갖고 있습니다. 예를 들어 103번 버스라고 가정해 보겠습니다. 그런데 103번 버스라는 것은 하나만 있는 것이 아닙니다. 즉, 우리가 알고 있는 103번 버스는 사실 "버스 번호"가 아니라 "노선 이름"입니다.<br /> <br /> 그런데, 공공데이터 Open API 내부에서는 이 "노선 이름"을 그대로 사용하지 않고 별도로 노선마다 코드화시킨 "ROUTE ID"를 사용합니다. 따라서, 우선 여러분들이 해야 할 것은, 사용자에게 친숙한 버스 번호(노선 이름)에 해당하는 "ROUTE ID"를 구해야 합니다.<br /> <br /> 이 정보는 2가지 방식으로 구할 수 있는데요,<br /> <br /> <ul> <li>CSV 파일: 서울특별시_버스노선ID 정보 (<a target='tab' href='https://www.data.go.kr/data/15051743/fileData.do'>https://www.data.go.kr/data/15051743/fileData.do</a>)</li> <li>오픈 API: 서울특별시_노선정보조회 서비스 (<a target='tab' href='https://www.data.go.kr/data/15000193/openapi.do'>https://www.data.go.kr/data/15000193/openapi.do</a>)</li> </ul> <br /> 어느 걸 써도 무방합니다. 단지, CSV 파일인 경우 해당 정보가 변경되었는지 항상 신경 써야 하므로 그냥 Open API를 신청해서 필요할 때마다 호출하는 것이 더 낫습니다.<br /> <br /> 따라서, "<a target='tab' href='https://www.data.go.kr/data/15000193/openapi.do'>서울특별시_노선정보조회 서비스</a>"를 "활용 신청"을 해 두고, 이후 얻게 되는 인증키를 이용해 (약 1시간 정도 기다린 후) API를 호출할 수 있습니다. 참고로, 제공되는 인증키가 2가지로 나오는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 일반 인증키(Encoding): PM5Q7Gf1M...[생략]...FGH5budmvWZZe1WAA%2FQ%3D%3D 일반 인증키(Decoding): PM5Q7Gf1M...[생략]...vWZZe1WAA/Q== </pre> <br /> "Decoding" 값이 원본이고, "Encoding" 값은 원본 "Decoding" 값을 URLEncode 시킨 것에 불과합니다.<br /> <br /> 만약, 키 정보를 POST 데이터에 싣는다면 Decoding 값을 사용해야겠지만, 대부분의 경우 GET 요청의 QueryString 문자열로 전달하기 때문에 Encoding 값을 쓰는 것이 맞습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 키까지 준비가 되었으면 본격적으로 "버스 번호"에 해당하는 "ROUTE ID"를 구해야겠지요. ^^ 이것은 "서울특별시_노선정보조회 서비스"가 제공하는 4가지 API 중에,<br /> <br /> <ol> <li>getRouteInfoItem: 노선 기본 정보 조회</li> <li>getRoutePathList: 노선의 지도상 경로를 리턴한다.</li> <li>getBusRouteList: 노선번호에 해당하는 노선 목록 조회</li> <li>getStaionsByRouteList: 노선별 경유 정류소 조회 서비스</li> </ol> <br /> getBusRouteList를 통해 구할 수 있습니다. 가령, 서울 103번 버스의 ROUTE ID를 알고 싶다면 다음과 같이 호출할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 형식) http://ws.bus.go.kr/api/rest/busRouteInfo/getBusRouteList?<span style='color: blue; font-weight: bold'>ServiceKey</span>={인증키(Encoding)}&<span style='color: blue; font-weight: bold'>strSrch</span>={버스번호} 예) http://ws.bus.go.kr/api/rest/busRouteInfo/getBusRouteList?<span style='color: blue; font-weight: bold'>serviceKey</span>=PM5Q7Gf1M...[생략]...FGH5budmvWZZe1WAA%2FQ%3D%3D&<span style='color: blue; font-weight: bold'>strSrch</span>=103 </pre> <br /> getBusRouteList API의 호출 결과는 strSrch에 지정한 문자열을 포함한 모든 버스들을 나열합니다. 따라서 위의 예제는 "103"을 지정했으므로 "103", "103성남"을 모두 포함한 결과를 반환합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="UTF-8"?> <ServiceResult> <comMsgHeader /> <msgHeader> <headerCd>0</headerCd> <headerMsg>정상적으로 처리되었습니다.</headerMsg> <itemCount>0</itemCount> </msgHeader> <msgBody> <itemList> <span style='color: blue; font-weight: bold'><busRouteId>100100008</busRouteId></span> <span style='color: blue; font-weight: bold'><busRouteNm>103</busRouteNm></span> <corpNm>삼화상운 02-936-6000</corpNm> <edStationNm>서울역</edStationNm> <firstBusTm>20210813043000</firstBusTm> <firstLowTm /> <lastBusTm>20210813230000</lastBusTm> <lastBusYn /> <lastLowTm /> <length>30.42</length> <routeType>3</routeType> <stStationNm>삼화상운</stStationNm> <term>9</term> </itemList> <itemList> <span style='color: blue; font-weight: bold'><busRouteId>204000060</busRouteId></span> <span style='color: blue; font-weight: bold'><busRouteNm>103성남</busRouteNm></span> <corpNm>경기</corpNm> <edStationNm>사당역</edStationNm> <firstBusTm>20210813050000</firstBusTm> <firstLowTm /> <lastBusTm>20210813222000</lastBusTm> <lastBusYn /> <lastLowTm /> <length>0</length> <routeType>8</routeType> <stStationNm>도촌동9단지앞</stStationNm> <term>40</term> </itemList> </msgBody> </ServiceResult> </pre> <br /> 결국, 결과 목록 중 busRouteNm == 103인 항목의 busRouteId(위의 경우 100100008)가 바로 우리가 원하는 "ROUTE ID"입니다. 자, 그럼 이제 버스가 다니는 정류장 목록을 구할 차례입니다. 이를 위해 제공하는 API가 getStaionsByRouteList이며, 다음과 같이 호출할 수 있고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > http://ws.bus.go.kr/api/rest/busRouteInfo/getStaionByRoute?<span style='color: blue; font-weight: bold'>serviceKey</span>=PM5Q7Gf1M...[생략]...FGH5budmvWZZe1WAA%2FQ%3D%3D&<span style='color: blue; font-weight: bold'>busRouteId</span>=100100008 (그나저나, get<span style='color: blue; font-weight: bold'>Staions</span>ByRouteList의 오탈자가 유독 눈에 띄는군요. ^^;) </pre> <br /> 아래와 같은 출력 결과를 얻을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="UTF-8"?> <ServiceResult> <comMsgHeader /> <msgHeader> <headerCd>0</headerCd> <headerMsg>정상적으로 처리되었습니다.</headerMsg> <itemCount>0</itemCount> </msgHeader> <msgBody> <itemList> <arsId>11493</arsId> <beginTm>04:30</beginTm> <busRouteId>100100008</busRouteId> <busRouteNm>103</busRouteNm> <direction>서울역</direction> <gpsX>127.05038</gpsX> <gpsY>37.627217</gpsY> <lastTm>23:00</lastTm> <posX>204446.7338618399</posX> <posY>458629.3414768302</posY> <routeType>3</routeType> <sectSpd>77</sectSpd> <section>110603736</section> <seq>1</seq> <span style='color: blue; font-weight: bold'><station>110000391</station></span> <stationNm>삼화상운</stationNm> <stationNo>11493</stationNo> <transYn>N</transYn> <fullSectDist>458</fullSectDist> <trnstnid>101000006</trnstnid> </itemList> ...[생략]... <itemList> <arsId>11493</arsId> <beginTm>06:11</beginTm> <busRouteId>100100008</busRouteId> <busRouteNm>103</busRouteNm> <direction>삼화상운</direction> <gpsX>127.05038</gpsX> <gpsY>37.627217</gpsY> <lastTm>01:04</lastTm> <posX>204446.7338618399</posX> <posY>458629.3414768302</posY> <routeType>3</routeType> <sectSpd>77</sectSpd> <section>110603736</section> <seq>71</seq> <span style='color: blue; font-weight: bold'><station>110000391</station></span> <stationNm>삼화상운</stationNm> <stationNo>11493</stationNo> <transYn>N</transYn> <fullSectDist>685</fullSectDist> <trnstnid>101000006</trnstnid> </itemList> </msgBody> </ServiceResult> </pre> <br /> 여기서 station 노드가 바로 정류장에 대한 ID 값을 담고 있는데, 특이하게 마지막에 나오는 정류장의 <station /> 값이 첫 번째 정류장의 값과 같습니다. (이런 건 좀 설명을 API 문서에 포함하고 있어야 하는데... 찾아 볼 수가 없군요. ^^;)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 자, 이렇게 해서 103번 버스에 대한 Route ID == 100100008 값과 해당 노선에 대한 정류장 정보를 구했다면 이제 운행 중인 103번 버스들의 "위치 정보"를 구해야 합니다. 그리고 이에 대해서는 별도로 분리돼 다음의 오픈 API를 신청해야 합니다. (하지만, 키는 동일합니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 서울특별시_버스위치정보조회 서비스: <a target='tab' href='https://www.data.go.kr/data/15000332/openapi.do'>https://www.data.go.kr/data/15000332/openapi.do</a> </pre> <br /> 위의 서비스에서 제공하는 API 중에, getBusPosByRouteSt가 버스들의 위치 정보를 반환하는데, 이를 위해서는 3개의 인자를 더 전달해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > busRouteId: 노선 ID startOrd: 시작 정류소 순번 endOrd: 종료 정류소 순번 형식) http://ws.bus.go.kr/api/rest/buspos/getBusPosByRouteSt?<span style='color: blue; font-weight: bold'>ServiceKey</span>={인증키(Encoding)}&<span style='color: blue; font-weight: bold'>busRouteId</span>={노선ID}&<span style='color: blue; font-weight: bold'>startOrd</span>={시작}&<span style='color: blue; font-weight: bold'>endOrd</span>={끝} 예) http://ws.bus.go.kr/api/rest/buspos/getBusPosByRouteSt?<span style='color: blue; font-weight: bold'>ServiceKey</span>=인증키&<span style='color: blue; font-weight: bold'>busRouteId</span>=100100118&<span style='color: blue; font-weight: bold'>startOrd</span>=1&<span style='color: blue; font-weight: bold'>endOrd</span>=13 </pre> <br /> 일단 busRouteId는 알겠고, startOrd와 endOrd가 좀 모호합니다. 아마도 getStaionByRoute의 결과로 나오는 정류소들 중 시작 정류소를 1로 매겨, (103번의 경우 총 71개의 정류소이므로) 71까지 지정할 수 있는 듯합니다. 따라서, 해당 103번 노선의 전체 구간에서 운행 중인 모든 버스를 나열하고 싶다면 이런 식으로 호출해야 하는 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > http://ws.bus.go.kr/api/rest/buspos/getBusPosByRouteSt?ServiceKey=인증키&busRouteId=100100118&<span style='color: blue; font-weight: bold'>startOrd=1&endOrd=71</span> </pre> <br /> 암튼 그렇게 해서 호출하면 다음과 같은 결과를 얻을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="UTF-8"?> <ServiceResult> <comMsgHeader /> <msgHeader> <headerCd>0</headerCd> <headerMsg>정상적으로 처리되었습니다.</headerMsg> <itemCount>0</itemCount> </msgHeader> <msgBody> <itemList> <busType>1</busType> <congetion>0</congetion> <dataTm>20210813174120</dataTm> <isFullFlag>0</isFullFlag> <span style='color: blue; font-weight: bold'><lastStnId>111000055</lastStnId></span> <plainNo>서울74사7258</plainNo> <span style='color: blue; font-weight: bold'><posX>192074.81815468223</posX> <posY>457188.67593660066</posY></span> <routeId>100100118</routeId> <sectDist>127</sectDist> <sectOrd>1</sectOrd> <sectionId>111702375</sectionId> <stopFlag>0</stopFlag> <tmX>126.910226</tmX> <tmY>37.614212</tmY> <vehId>111033058</vehId> </itemList> ...[생략]... <itemList> <busType>1</busType> <congetion>3</congetion> <dataTm>20210813174645</dataTm> <isFullFlag>0</isFullFlag> <span style='color: blue; font-weight: bold'><lastStnId>119000021</lastStnId></span> <plainNo>서울75사2646</plainNo> <span style='color: blue; font-weight: bold'><posX>193600.89437542975</posX> <posY>446520.18564428296</posY></span> <routeId>100100118</routeId> <sectDist>1054</sectDist> <sectOrd>66</sectOrd> <sectionId>119700532</sectionId> <stopFlag>0</stopFlag> <tmX>126.927606</tmX> <tmY>37.518091</tmY> <vehId>111033668</vehId> </itemList> </msgBody> </ServiceResult> </pre> <br /> 위의 데이터에서 posX, posY GPS 정보를 읽어오면 현재 버스의 위치를 지도 상에서 대략 알 수 있을 것입니다. 그런데, 버스 앱을 사용해 보신 분은 아시겠지만 지도 상의 버스 위치는 사실 관심 사항이 아닙니다. 즉, 현재 버스가 정류장 기준으로 어느 위치에 있는지를 사용자는 알고 싶은 것입니다. 하지만, 이 값을 어떻게 구할 수 있는지에 대해 명시적인 문서 정보가 없습니다. 공식 문서를 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 서울특별시_버스위치정보조회_서비스_활용가이드_20190110.docx ; <a target='tab' href='https://www.data.go.kr/cmm/cmm/fileDownload.do?atchFileId=FILE_000000001498296&fileDetailSn=0'>https://www.data.go.kr/cmm/cmm/fileDownload.do?atchFileId=FILE_000000001498296&fileDetailSn=0</a> </pre> <br /> getBusPosByRouteSt API의 결과에 대한 필드 설명을 다음과 같이 하고 있는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > sectOrd 구간순번 string 구간순번 sectDist 구간옵셋거리(Km) string 구간옵셋거리(Km) stopFlag 정류소도착여부 string 정류소도착여부 (0:운행중, 1:도착) sectionId 구간 ID string 구간 ID dataTm 제공시간 string 제공시간 tmX 맵매칭X좌표 (WGS84) string 맵매칭X좌표 (WGS84) tmY 맵매칭Y좌표 (WGS84) string 맵매칭Y좌표 (WGS84) vehId 버스 ID string 버스 ID plainNo 차량번호 string 차량번호 busType 차량유형 string 차량유형 (0:일반버스, 1:저상버스, 2:굴절버스) lastStnId 최종정류장ID string 최종정류장ID posX 맵매칭X좌표 (GRS80) string 맵매칭X좌표 (GRS80) posY 맵매칭Y좌표 (GRS80) string 맵매칭Y좌표 (GRS80) routeId 노선 ID string 노선 ID </pre> <br /> "구간순번(sectOrd)"이 아마도 현재 운행 중인 구간으로 보입니다. 그리고 "최종정류장ID(lastStnId)"는 단어 그대로 보면 마지막 정류장의 Station ID를 의미하는 것 같은데, 실제로 API 결과를 보면 마지막으로 지나온 정류장을 의미하는 듯합니다. (그렇습니다, API를 사용하는 측에서 이게 무슨 값을 의미하는지 알아서 해석해야 합니다. ^^; 혹시, 틀렸다면 덧글 부탁드립니다.)<br /> <br /> 위의 내용 정도를 이해한다면, 마찬가지로 2개로 나뉜 경기도 버스 정보 API도 쉽게 사용할 수 있을 것입니다. ^^<br /> <br /> <ul> <li>경기도_버스노선 조회: <a target='tab' href='https://www.data.go.kr/data/15080662/openapi.do'>https://www.data.go.kr/data/15080662/openapi.do</a></li> <li>경기도_버스위치정보 조회: <a target='tab' href='https://www.data.go.kr/data/15080648/openapi.do'>https://www.data.go.kr/data/15080648/openapi.do</a></li> </ul> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, 분명히 API 활용 신청을 했고 승인도 났는데 다음의 오류를 보게 된다면?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="UTF-8"?> <ServiceResult> <comMsgHeader /> <msgHeader> <headerCd>7</headerCd> <headerMsg>Key인증실패: SERVICE KEY IS NOT REGISTERED ERROR.[인증모듈 에러코드(30)]</headerMsg> <itemCount>0</itemCount> </msgHeader> <msgBody /> </ServiceResult> </pre> <br /> 성격이 급하신 것입니다. ^^ 어떤 글에는 10분 기다리면 된다고 하는데, 제 경우에는 승인 후에도 1시간 넘게 기다려야 정상적으로 API를 사용할 수 있었습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 기타, OpenAPI 관련 테스트를 할 수 있는 여러 소스들...<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 서울 열린 데이터 광장 ; <a target='tab' href='https://data.seoul.go.kr'>https://data.seoul.go.kr</a> 고속도로 공공 데이터 포털 ; <a target='tab' href='http://data.ex.co.kr'>http://data.ex.co.kr</a> 교통 사고 분석 시스템 ; <a target='tab' href='http://taas.koroad.or.kr'>http://taas.koroad.or.kr</a> 국가 통계 포털 ; <a target='tab' href='http://kosis.kr/index/index.do'>http://kosis.kr/index/index.do</a> 기상 자료 개방 포털 ; <a target='tab' href='https://data.kma.go.kr'>https://data.kma.go.kr</a>, <a target='tab' href='http://sts.kma.go.kr'>http://sts.kma.go.kr</a> 영화 진흥 위원회 영화 DB ; <a target='tab' href='http://www.kofic.or.kr'>http://www.kofic.or.kr</a> SNS - 트위터: <a target='tab' href='https://developer.twitter.com'>https://developer.twitter.com</a> - 네이버 블로그 검색: <a target='tab' href='https://developers.naver.com/docs/search/blog/'>https://developers.naver.com/docs/search/blog/</a> - 네이버 뉴스 검색: <a target='tab' href='https://developers.naver.com/docs/search/news/'>https://developers.naver.com/docs/search/news/</a> </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1479
(왼쪽의 숫자를 입력해야 합니다.)