버스 잔여좌석 제공 프로젝트 목차
공공데이터에서 파싱해올 데이터 가져오기
이 프로젝트에서 사용할 가장 대표적인 API 두개이다. 두 API 모드 REST 방식으로 XML파일로 데이터를 제공하며, 친절하게 API문서도 제공한다. (공공데이터에서 검색 시 쉽게 찾을 수 있다.)
버스 위치 정보 조회 서비스
이 프로젝트의 핵심 API이다.
인증키와 routeId(버스 노선번호가 아닌, 버스에 부여된 ID를 의미한다.) 를 넣고 REST API에 요청을 보내면,
comMsgHeader 는 공통 메시지 헤더를 의미하고, msgHeader에는 처리 시간과 리턴 코드, 그리고 결과 메시지가 출력된다.
우리가 필요한 정보는 msgBody에 존재하며, 실시간으로 운행중인 버스의 정보가 들어있다.
버스의 번호와 Id, 그리고 가장 핵심인 remainSeatCnt, 잔여좌석이 제공된다!
이 데이터들을 주기적으로 파싱해 테이블에 쌓아두는 파이썬 코드를 작성해 서버에 돌려놓고 있는데, 이는 밑에 소개하겠다.
버스노선 조회 서비스
위에서 수집한 버스의 실시간 위치 정보에는 잔여좌석 외에도 stationId, stationSeq 등 정류장에 대한 정보도 존재한다.
좌석정보를 아무리 모아도 버스의 잔여좌석은 시간과 장소에 따라 천차만별로 차이가 심하다.
따라서 평균적으로 몇시에 어떤 정류장에서 몇 석의 잔여좌석이 존재했었는지를 제공하는 것이 중요하기 때문에 노선별 정류장 정보들 또한 DB에 저장해 놓기로 했다.
이 테이블은 거의 변동되지 않기 때문에 한번에 파싱해 테이블과 컬럼들을 생성하는 방식의 파이썬 코드를 작성했다.
버스 노선 조회 서비스 파싱 예시 [Python]
#-*- coding:utf-8 -*-
"""
잔여좌석 넣는다.
"""
import urllib.request
import xml.etree.ElementTree as et
import time, sys
from datetime import datetime
from db_control import *
class bus:
def __init__(self):
self.serviceKey = 'Your API key'
"""
curs.execute('select stationId from stationId where station_num="%s"'%(self.stationNum))
result = curs.fetchall()
self.stationId = result[0][0]
#print(self.stationId)
curs.close()
"""
def remainSeat(self):#잔여좌석 가져온닷
db = dbcontrol('bus')
db.execute('select areaid, routeName, routeId from bus_info where areaid=29 or areaid=18 or areaid=25')
#일단은 포천,의정부, G1300
bus_list = db.fetchall()
for bus in bus_list:
areaid = bus[0]
routeName = bus[1]
routeId = bus[2]
url = 'http://openapi.gbis.go.kr/ws/rest/buslocationservice?serviceKey=%s&routeId=%s'%(self.serviceKey, routeId)
response = urllib.request.urlopen(url)
data = response.read()
tree = et.fromstring(data)
for data in tree.iter('comMsgHeader'):
returnCode = data.findtext('returnCode')
if returnCode == '22': # API 이용 제한시 출력되는 return code
return 2
for data in tree.iter('busLocationList'):
remainSeat = data.findtext('remainSeatCnt')
stationSeq = data.findtext('stationSeq')
plateType = data.findtext('plateType') # 3 = 일반 대형버스 , 4 = 2층버스
now = time.localtime()
nowtime = "%04d-%02d-%02d %02d:%02d:%02d" % (now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec)
db.execute("insert into `%s_%s`(date, plateType, remainSeat, stationSeq) values ('%s', %s, %s, %s)"%(areaid, routeName, nowtime, plateType, remainSeat, stationSeq))
db.commit()
db.close()
test = bus()
count = 0
while(True):
now = datetime.now()
if(now.hour > 0 and now.hour <5 ): # 버스가 운행하지 않는 1시경부터 4시경까지는 멈춤
print("sleep..")
with open("log", "a") as f:
text = "Sleep in " + str(now) + "\n"
f.write(text)
count=0
time.sleep(3600*5)
with open("log", "a") as f: # 로그 기록
text = "[+] Success time : " + str(now) + " count : " + str(count) + "\n"
f.write(text)
tmp = test.remainSeat()
if tmp == 2: # API 이용 가능 횟수 초과시 Limited 로그 기록
with open("log", "a") as f:
text = "[+] Limited : " + str(now) + " count : " + str(count) + "\n"
f.write(text)
count += 1
time.sleep(600) # 10분 간격 파싱
(Python을 이용한 XML 파싱 정보들은 구글에 아주 많습니다!)
현재는 이용 제한 횟수 제한으로 주로 이용하는 노선들만 파싱하고 있다.
remainSeat에서 areaid, routeName, routeId는 각각 지역아이디, 노선번호, 노선ID를 의미하는데, 이 정보들이 담긴 bus_info는 이렇게 구성되어 있다.
직행좌석버스(경기도) - 나무위키
이 저작물은 CC BY-NC-SA 2.0 KR에 따라 이용할 수 있습니다. (단, 라이선스가 명시된 일부 문서 및 삽화 제외) 기여하신 문서의 저작권은 각 기여자에게 있으며, 각 기여자는 기여하신 부분의 저작권�
namu.wiki
여기서 직접 리스트를 작성해 테이블에 넣어놓았다. 이 목록들이 필요하신분은
#-*-coding:utf-8-*-
#직행좌석버스
area_bus = [
["가평군","1330-2","1330-3","1330-4","1330-44","8005"],
["고양시","1000","1001","1082","1100","1200","1500","1900","3300","9700"], #9600번 전체에선 뜨는데 지역에선안뜸
["광명시","3001","3002","8507"],
["광주시", "500-1","500-1A","1005","1113","1113-1","1113-2","1117","1150","1303","1500-2","3500","5500-2","3200",
"7007-1","9000","9000-1","9600","1550","1560","1570","5006","5007","1007","1007-1","1009","1112","1551","1311","1550-1","6501",
"9301"],
["구리시", "1115-6", "1650", "1680"],
["김포시", "1004","2000", "3000", "3000A","6427","M6427","7000","8000","9000","9008","G6001"],#2000번 두개임 손으로해줬음
["남양주시", "11","100","105","1000","1000-1","1001","1003","1100","1200","1660","1670","1700","2000","7007"],
["성남시","102","333","1151","1241","3330","4000","6900","9003","9004","9007","9300","9407","9507","9607"],
#["용인시","1550","1560","1570","5006","5007","9000-1"],
["수원시","2007","3000","3002","3003","3007","5100","5300","7000","7002","7770","7780","7790","7800"],#4000번 확인해야댐 "7900" 사라짐
#["오산시",,"1550-1"],
# ["군포시","6501"],
#["파주시", "2000"],
["시흥시","3200","3300","3400"],
["안산시","3100","3101","3102","5609"],
["안양시","3030"],
["양주시","1100","G1300"],
["용인시","5000B","5001","5001-1","5002","5003B","5005","5600","5700"],#"5000-1","5000"없음 #5000A 있는데 안다님
["파주시","200","2200","M7111","9030","9030-1","9710","9710-1"],
["하남시", "3000","9302","9303","9303-1","9304"],
["화성시","1002","1008","6001","6002","6002-1","6003","6004","8155","8156","8471","8472","9802"], #8156(급행) 넣어줘야댄다
["포천시","1386","3100","3200","3500","3600"],
["의정부시","G6000"]
]
area_id = {
"가평군": "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"
}
"""
for bus in area_bus:
for a in bus:
print(a)
"""
#확인불가
#용인 5000A,5003A (2019.09.28)
#파주 G7111,
이 리스트는 모든 노선 정보가 담겨있지 않으며, 정확하지 않은 정보입니다. 임의 이용시 제게 책임을 묻지 마세요..
그리고 위의 코드를 실행시켜 파싱되는 정보들은 다음과 같다.
버스노선 조회 서비스 파싱 예시 [Python]
#-*- coding:utf-8 -*-
from db_control import *
import urllib.request
import xml.etree.ElementTree as et
from list import *
class create_table: # ex . ('31', '8156', '233000258', '서울,의왕,화성')
def __init__(self):
self.serviceKey = 'Your API key'
def createBusInfo(self):
# info_list로 버스마다 경유하는 정류장들의 정보를 담은 테이블 생성
# DB : busStationInfo // doc : GB202, No2.경유정류소목록조회
curs = dbcontrol('bus')
curs.execute('select * from bus_info')
info_list = curs.fetchall()
curs2 = dbcontrol('busStationInfo')
for info in info_list:
url = "http://openapi.gbis.go.kr/ws/rest/busrouteservice/station?serviceKey=%s&routeId=%s"%(self.serviceKey, info[2])
response = urllib.request.urlopen(url)
result = response.read()
tree = et.fromstring(result)
routeName = info[1]
#if "-" in routeName:
# routeName = routeName.replace("-", "\-")
try:
curs2.execute('create table `%s_%s`(stationName varchar(40), mobileNo INT, stationId INT, stationSeq INT, regionName varchar(10), districtCd INT, centerYn varchar(5), turnYn varchar(5),x varchar(20), y varchar(20))'%(info[0], routeName))
for data in tree.iter('busRouteStationList'):
stationId = data.findtext("stationId")
mobileNo = data.findtext("mobileNo")
regionName = data.findtext("regionName")
turnYn = data.findtext("turnYn")
centerYn = data.findtext("centerYn")
districtCd = data.findtext("districtCd")
stationName = data.findtext("stationName")
station_x = data.findtext("x")
station_y = data.findtext("y")
stationSeq = data.findtext("stationSeq")
if mobileNo == None:
curs2.execute("insert into `%s_%s`(stationName, stationId, stationSeq, regionName, districtCd , centerYn, turnYn, x, y) values ('%s', %s, %s, '%s', %s, '%s', '%s', '%s', '%s')"%(info[0], routeName, stationName, stationId, stationSeq ,regionName, districtCd , centerYn, turnYn, station_x, station_y))
else:
curs2.execute("insert into `%s_%s`(stationName, mobileNo, stationId, stationSeq, regionName, districtCd , centerYn, turnYn, x, y) values ('%s', %s, %s, %s, '%s', %s, '%s', '%s', '%s', '%s')"%(info[0], routeName, stationName, mobileNo, stationId, stationSeq ,regionName, districtCd , centerYn, turnYn, station_x, station_y))
except Exception as e:
print(e)
print("name : %s" %(routeName))
curs2.close()
curs.close()
print("[+] Success createbusinfo")
a = create_table()
a.createBusInfo()
이 코드로 생성되는 DB 정보는
이렇게 구성되며, 다시 API에 접근할 필요없이 한번만 파싱해오면 DB에서 언제든지 꺼내 쓸 수 있다.
의식의 흐름대로 작성하다보니 앞뒤가 맞지 않을 수도 있지만.. 이는 앞으로 차차 다듬어 갈 예정입니다..
'그 외' 카테고리의 다른 글
NAVER CLOUD PLATFORM Hands-on Lab 후기 (0) | 2020.09.24 |
---|---|
MariaDB에서 Node.js를 통해 datetime 관련 이슈 (0) | 2020.09.10 |
1. go 의 if, switch, for, 함수 (0) | 2020.09.09 |
[DB] MySQL 비정상 정지시 복구 (InnoDB, MyISAM) (0) | 2020.09.09 |
[Go] 0. go 특징 (0) | 2020.09.07 |