DB
- ShowingData - 영화관 상영 정보
- MovieID varchar(100) - name_개봉날짜(MovieData에서 ID를 꺼내옴)
- MovieName text - 더 퍼스트 슬램덩크
- MovieNameEN text - The First Slam Dunk
- Movietheater text - CGV, LotteCinema, MegaBox - 영화관
- ScreenKR text - 영화관 3관, 4관
- ScreenEN text - Cinema 3, 4
- PlayKind text - 2d, 3d, 4dx 2d, 2d(자막)
- Date text - 2023-03-03
- RunningTime integer - 220
- StartTime text - 10:30
- EndTime text - 14:10
- TicketPage text - 예약 사이트 링크
- TheaterData - 영화관 정보
- Movietheater text - cgv, lottecinema, megabox
- Name text - 강남점, 홍대점
- NameEN text - gangnam, hongdae
- TheaterCode text - 구분 코드
- city text - 서울
- Addr text - 서울시 금천구 ~
- AddrEN text - seoul ~
MegaBox
MEET PLAY SHARE, 메가박스
사람들과 공유할 수 있는, 공간경험을 만듭니다.
www.megabox.co.kr
상영 날짜 리스트가 유니코드로 인하여 에러가나서 모바일 api로 바꿨으나 바꿔도 에러가 납니다.
웹 api로 다시 돌려놓고 수정하여 해결했습니다.

에러는 창원내서 에서만 3월 9일이나 8일쪽 파싱이 뭔가 문제가 있나봅니다...

친절하게도 파싱사이트에 넘겨주니 어디가 문젠지 알려줍니다..
도대체 왜 저기 따옴표가 2개가 들어가있을까요...? 유니코드로도 따옴표를 넣었나봅니다
replace("\"\"", "\"")
를 붙여주니 에러가 안납니다...
영화 날짜 리스트 및 영화관 정보는 해당 api 사용 - Date, TheaterData, showingData 해결



도시와 영화관 리스트는 단순 크롤링으로 해결
단, 도시는 묶여있는 경우가 있으므로 가져온 주소에서 앞 2글자만 가져와 도시로 사용
강원도 원주시 황금로 2, 센트럴파크 7층 -> 강원

코드
fun getMBDatesNTheaters(brchNo: String, brchName: String): Pair<Triple<String, String, String>, ArrayList<String>> {
val url = mburl + "/on/oh/ohc/Brch/schedulePage.do"
val paramlist = HashMap<String, String>()
paramlist["brchNm"] = brchName
paramlist["brchNo"] = brchNo
paramlist["brchNo1"] = brchNo
paramlist["firstAt"] = "Y"
paramlist["masterType"] = "brch"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.data(paramlist)
.ignoreContentType(true)//에러나면 추가
val doc = conn.post().text().replace("\"\"", "\"")
val datemap = ArrayList<String>()
val megamap = JSONObject(doc).getJSONObject("megaMap")
val showtimes = megamap.getJSONArray("movieFormDeList")
val theaterinfo = megamap.getJSONObject("brchInfo")
val addr = theaterinfo.getString("roadNmAddr")
val addrEN = theaterinfo.getString("engAddr")
val brchEN = theaterinfo.getString("brchEngNm")
for (i in 0 until showtimes.length()) {
val showtime = showtimes.getJSONObject(i)
val date = showtime.getString("playDe")
datemap.add(date)
}
return Pair(Triple(addr, addrEN, brchEN), datemap)
}
fun getMBTheaters(): ArrayList<HashMap<String, String>> {
val theaterlist = ArrayList<HashMap<String, String>>()
val url = mburl + "/theater/list"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
val doc = conn.get()
val cities = doc.getElementsByClass("theater-place")[0].getElementsByTag("button")
val theaters = doc.getElementsByClass("theater-list")
for (i in 0 until cities.size) {
val cityName = cities.get(i).getElementsByClass("sel-city")[0].text()
val theaterDatas = theaters.get(i).getElementsByTag("li")
for (theater in theaterDatas) {
val theatermap = HashMap<String, String>()
val brchNo = theater.attr("data-brch-no")
val brchName = theater.text()
theatermap.put("city", cityName)
theatermap.put("brchNo", brchNo)
theatermap.put("brchName", brchName)
theaterlist.add(theatermap)
}
}
return theaterlist
}
fun getMBShowtimes(theaters: ArrayList<HashMap<String, String>>): Unit {
val url = mburl + "/on/oh/ohc/Brch/schedulePage.do"
for (theater in theaters) {
val brchKR = theater["brchName"] ?: ""
val brchNo = theater["brchNo"] ?: ""
val (theater, dates) = getMBDatesNTheaters(brchNo, brchKR)
val (addr, addrEN, brchEN) = theater
val city = addr.substring(0..1)
println("${city} ${brchKR} ${brchEN} ${brchNo}\n${addr}\n${addrEN}")
for (date in dates) {
val paramlist = HashMap<String, String>()
paramlist["brchNm"] = brchKR
paramlist["brchNo"] = brchNo
paramlist["brchNo1"] = brchNo
paramlist["masterType"] = "brch"
paramlist["playDe"] = date
paramlist["firstAt"] = "N"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.data(paramlist)
.ignoreContentType(true)//에러나면 추가
val doc = conn.post().body().text()
val showtimes = JSONObject(doc).getJSONObject("megaMap").getJSONArray("movieFormList")
println("${date}")
for (i in 0 until showtimes.length()) {
val showtime = showtimes.getJSONObject(i)
val totalSeat = showtime.getInt("totSeatCnt")
val restSeat = showtime.getInt("restSeatCnt")
val playSchldNo = showtime.getString("playSchdlNo")
val startTime = showtime.getString("playStartTime")
val endTime = showtime.getString("playEndTime")
val runnigTime = showtime.getString("moviePlayTime")
val movieNm = showtime.getString("rpstMovieNm")
val movieNmEN = showtime.get("movieEngNm") ?: ""
val playKind = showtime.getString("playKindNm")
val ExpoNm = showtime.getString("theabExpoNm")
val ticketPage = "https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=${playSchldNo}"
println("${movieNm} ${movieNmEN} ${playKind} ${ExpoNm} ${ticketPage}\n${totalSeat} ${restSeat}\n${startTime} ${endTime} ${runnigTime}\n")
}
}
}
}
경상 창원내서 Megabox Changwon Naeseo Branch 0014
경상남도 창원시 마산회원구 내서읍 광려천서로 81, (내서읍) ISC프라자 10층
81, Gwangnyeocheonseo-ro, Naeseo-eup, Masanhoewon-gu, Changwon-si, Gyeongsangnam-do, Republic of Korea
20230304
더 퍼스트 슬램덩크 The First Slam Dunk 2D(자막) 컴포트 1관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014090
87 75
19:40 21:55 125
대외비 The Devil's Deal 2D 컴포트 3관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014096
90 87
21:25 23:30 115
대외비 The Devil's Deal 2D 컴포트 4관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014055
90 63
19:40 21:45 115
대외비 The Devil's Deal 2D 컴포트 4관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014056
90 87
22:00 24:05 115
대외비 The Devil's Deal 2D 컴포트 5관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014062
115 105
20:50 22:55 115
멍뭉이 My Heart Puppy 2D 컴포트 3관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014071
90 82
19:00 21:03 113
앤트맨과 와스프: 퀀텀매니아 Ant-Man and the Wasp: Quantumania 2D(자막) 컴포트 1관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014091
87 85
22:10 24:24 124
아바타: 물의 길 Avatar: The Way of Water 3D(자막) 좋은데이관(컴포트 2관-리클라이너) https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303040014084
115 104
21:05 24:27 192
20230305
스즈메의 문단속 Suzume 2D(자막) 컴포트 3관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303050014034
90 63
14:05 16:17 122
더 퍼스트 슬램덩크 The First Slam Dunk 2D(자막) 컴포트 1관[리클라이너] https://www.megabox.co.kr/bookingByPlaySchdlNo?playSchdlNo=2303050014014
87 85
17:30 19:45 125
롯데시네마
https://www.lottecinema.co.kr/
롯데시네마
www.lottecinema.co.kr
롯데시네마의 경우 영어 주소가 없어 그냥 빈 스트링 처리 했습니다.



주소 관련



영화관 정보를 가져오던 api는 주소가 없는 경우도 있어서 위의 api를 사용해야 할 듯 합니다.


춘천의 경우 Address가 들어가 있지 않습니다...?


도시를 따로 저장한 뒤 detaildivisioncode로 찾아야 할 것 같습니다... 많이 귀찮네요...
만일의 경우를 대비하려면 divisionCode와 detailDivisionCode를 둘 다 사용해야 할 것 같습니다..
그냥 문자열로 합쳐서 사용합시다.
divisionCode를 뒤지다 보니 2의 경우 특별관만 따로 가져오는 것 같습니다.
divisionCode가 2인 경우는 시간표에서 무시하고 넘어갑시다.

1만 가져와도 모든 데이터를 가져와 줍니다.
근데 문제는 춘천만 주소가 없네요... 그냥 강원으로 강제로 넣어주겠습니다..
영화관 이름에 씨네 패밀리나 샤롯데 같은 특별관들은 포함이 안되어 있습니다.
이것 또한 따로 찾아서 합쳐줘야 합니다.
예약 주소 바로이동 패턴
https://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=102307&link_cinemaCode=1023&link_movieCd=19551&link_date=2023-03-04&link_time=17:00&link_channelCode=naver
llink_screenID
link_cinemaCode
link_movieCd
link_date
link_time
link_channelCode = naver
코드
fun getLCAddr(divisionCode: String, detailDivisionCode: String, cinemaID: String): String {
val url: String =
LCurl + "/LCWS/Cinema/CinemaData.aspx"
var paramlist = HashMap<String, Any>()
paramlist["MethodName"] = "GetCinemaDetailItem"
paramlist["channelType"] = "HO"
paramlist["osType"] = "Chrome"
paramlist["osVersion"] = userAgent
paramlist["divisionCode"] = divisionCode
paramlist["detailDivisionCode"] = detailDivisionCode
paramlist["cinemaID"] = cinemaID
paramlist["memberOnNo"] = "0"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.data("ParamList", JSONObject(paramlist).toString())
val doc = conn.post().body().text()
val data = JSONObject(doc)
val Addr = data.getJSONObject("CinemaDetail").getString("Address")
return Addr
}
fun getLCTheaters(): ArrayList<HashMap<String, Any>> {
val theaterlist = ArrayList<HashMap<String, Any>>()
val url: String =
LCurl + "/LCWS/Cinema/CinemaData.aspx"
var paramlist = HashMap<String, Any>()
paramlist["MethodName"] = "GetCinemaItems"
paramlist["channelType"] = "HO"
paramlist["osType"] = "W"
paramlist["osVersion"] = userAgent
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.data("ParamList", JSONObject(paramlist).toString())
val doc = conn.post().body().text()
val data = JSONObject(doc)
val cinemas = data.getJSONObject("Cinemas").getJSONArray("Items")
for (i in 0 until cinemas.length()) {
val cinema = cinemas.getJSONObject(i)
val brchKR = "롯데시네마 " + cinema.getString("CinemaName") + "점"
val brchEN = "LotteCinema " + cinema.getString("CinemaNameUS")
val divisionCode = cinema.get("DivisionCode").toString()
val detailDivisionCode = cinema.getString("DetailDivisionCode")
val cinemaID = cinema.get("CinemaID").toString()
if (divisionCode == "2")
continue
val theatermap = HashMap<String, Any>()
theatermap["brchEN"] = brchEN
theatermap["brchKR"] = brchKR
theatermap["divisionCode"] = divisionCode
theatermap["detailDivisionCode"] = detailDivisionCode
theatermap["cinemaID"] = cinemaID
var addr = getLCAddr(divisionCode, detailDivisionCode, cinemaID)
if (brchKR == "롯데시네마 춘천점")
addr = "강원도 춘천시 중앙로67번길 18 (죽림동)"
theatermap["addr"] = addr
theatermap["city"] = addr.substring(0..1)
theaterlist.add(theatermap)
}
return theaterlist
}
fun getLCTicketAddr(data: JSONObject): String {
val screenID = data.get("ScreenID").toString()
val cinemaCode = data.get("CinemaID").toString()
val movieCd = data.getString("MovieCode")
val date = data.getString("PlayDt")
val startTime = data.getString("StartTime")
val ticketPage =
LCurl + "/NLCHS/ticketing?link_screenId=${screenID}&link_cinemaCode=${cinemaCode}&link_movieCd=${movieCd}&link_date=${date}&link_time=${startTime}&link_channelCode=naver"
return ticketPage
}
fun getLCDates(theatercode: String): ArrayList<String> {
var datelist = ArrayList<String>()
val url: String =
LCurl + "/LCWS/Ticketing/TicketingData.aspx"
var paramlist = HashMap<String, Any>()
paramlist.put("MethodName", "GetInvisibleMoviePlayInfo")
paramlist.put("channelType", "HO")
paramlist.put("osType", "W")
paramlist.put("osVersion", userAgent)
paramlist.put("cinemaList", theatercode)
paramlist.put("movieCd", "")
paramlist.put("playDt", "2023-03-03")
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.data("ParamList", JSONObject(paramlist).toString())
val doc = conn.post().body().text()
val data = JSONObject(doc).getJSONObject("PlayDates").getJSONArray("Items")
for (i in 0 until data.length()) {
val playdate = data.getJSONObject(i).getString("PlayDate").split(" ")
datelist.add(playdate[0])
}
return datelist
}
fun getRunnigTime(startTime: String, endTime: String): Int {
val end = endTime.split(":")
val start = startTime.split(":")
return end[0].toInt() * 60 + end[1].toInt() - start[0].toInt() * 60 - start[1].toInt()
}
fun getLCShowtimes(theaterlist: ArrayList<HashMap<String, Any>>): Unit {
for (theater in theaterlist) {
val brchKR = theater["brchKR"]
val brchEN = theater["brchEN"]
val divisionCode = theater["divisionCode"].toString() ?: ""
val detailDivisionCode = theater["detailDivisionCode"].toString() ?: ""
val cinemaID = theater["cinemaID"].toString() ?: ""
val cinemaCode: String =
"${divisionCode}|${detailDivisionCode}|${cinemaID}"
val datelist = getLCDates(cinemaCode)
val addr = theater["addr"]
val city = theater["city"]
println("${city} ${brchKR} ${brchEN} ${cinemaCode} \n${addr}")
for (date in datelist) {
val url: String =
LCurl + "/LCWS/Ticketing/TicketingData.aspx"
var paramlist = HashMap<String, String>()
paramlist["MethodName"] = "GetPlaySequence"
paramlist["channelType"] = "HO"
paramlist["osType"] = "W"
paramlist["osVersion"] = userAgent
paramlist["playDate"] = date
paramlist["cinemaID"] = cinemaCode
paramlist["representationMovieCode"] = ""
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.data("ParamList", JSONObject(paramlist).toString())
val doc = conn.post().body().text()
val data = JSONObject(doc)
val playSeqs = data.getJSONObject("PlaySeqs").getJSONArray("Items")
val playHeaders = data.getJSONObject("PlaySeqsHeader").getJSONArray("Items")
val translation = HashMap<Int, String>()
println("${date}")
for (i in 0 until playHeaders.length()) {
val headerdata = playHeaders.getJSONObject(i)
val translationCode = headerdata.getInt("TranslationDivisionCode")
val translationName = headerdata.getString("TranslationDivisionNameKR")
translation[translationCode] = translationName
}
for (i in 0 until playSeqs.length()) {
val playdata = playSeqs.getJSONObject(i)
val movieNameKR = playdata.get("MovieNameKR")
val movieNameUS = playdata.get("MovieNameUS")
val screenDivisionCode = playdata.getInt("ScreenDivisionCode")
var screenDivisionKR = ""
var screenDivisionEN = ""
if (screenDivisionCode != 100 && playdata.getString("ScreenDivisionNameKR") != playdata.get("ScreenNameKR")) {
screenDivisionKR = playdata.getString("ScreenDivisionNameKR") + " "
screenDivisionEN = playdata.getString("ScreenDivisionNameUS") + " "
}
val screenKR = screenDivisionKR + playdata.get("ScreenNameKR")
val screenEN = screenDivisionEN + playdata.get("ScreenNameUS")
val startTime = playdata.getString("StartTime")
val endTime = playdata.getString("EndTime")
val totalSeat = playdata.get("TotalSeatCount")
val restSeat = playdata.get("BookingSeatCount")
val translationCode = playdata.getInt("TranslationDivisionCode")
val runnigTime = getRunnigTime(startTime, endTime)
var playKind = playdata.getString("FilmNameKR")
if (translationCode != 900)
playKind + "(${translation[translationCode]})"
val ticketPage = getLCTicketAddr(playdata)
println("${movieNameKR} ${movieNameUS} ${playKind}\n${screenKR} ${screenEN}\n${startTime} ${endTime} ${runnigTime}\n${totalSeat} ${restSeat} ${ticketPage}")
}
}
}
}
부산 롯데시네마 부산본점점 LotteCinema Busan 1|0101|2004
부산 부산진구 가야대로 772 (부전동)
2023-03-04
대외비 The Devil's Deal 2D
5관 CINEMA 5
22:45 24:50 125
262 253 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200405&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-04&link_time=22:45&link_channelCode=naver
대외비 The Devil's Deal 2D
6관 CINEMA 6
21:50 23:55 125
270 242 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200406&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-04&link_time=21:50&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
21:00 23:05 125
237 195 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-04&link_time=21:00&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
23:20 25:25 125
237 229 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-04&link_time=23:20&link_channelCode=naver
더 퍼스트 슬램덩크 The First Slam Dunk 2D
8관 CINEMA 8
22:20 24:35 135
237 224 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200408&link_cinemaCode=2004&link_movieCd=19452&link_date=2023-03-04&link_time=22:20&link_channelCode=naver
앤트맨과 와스프: 퀀텀매니아 Ant-Man and the Wasp: Quantumania 2D
7관 CINEMA 7
22:00 24:14 134
211 200 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200407&link_cinemaCode=2004&link_movieCd=19562&link_date=2023-03-04&link_time=22:00&link_channelCode=naver
서치 2 Missing 2D
2관 CINEMA 2
20:55 22:55 120
157 133 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200402&link_cinemaCode=2004&link_movieCd=19514&link_date=2023-03-04&link_time=20:55&link_channelCode=naver
서치 2 Missing 2D
2관 CINEMA 2
23:10 25:10 120
157 153 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200402&link_cinemaCode=2004&link_movieCd=19514&link_date=2023-03-04&link_time=23:10&link_channelCode=naver
카운트 카운트 2D
3관 CINEMA 3
21:05 23:04 119
157 137 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200403&link_cinemaCode=2004&link_movieCd=19538&link_date=2023-03-04&link_time=21:05&link_channelCode=naver
카운트 카운트 2D
3관 CINEMA 3
23:20 25:19 119
157 151 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200403&link_cinemaCode=2004&link_movieCd=19538&link_date=2023-03-04&link_time=23:20&link_channelCode=naver
더 웨일 The Whale 2D
4관 CINEMA 4
23:05 25:12 127
157 157 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200404&link_cinemaCode=2004&link_movieCd=19589&link_date=2023-03-04&link_time=23:05&link_channelCode=naver
크리드 3 Creed III 2D
10관 CINEMA 10
21:50 23:56 126
144 144 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200410&link_cinemaCode=2004&link_movieCd=19582&link_date=2023-03-04&link_time=21:50&link_channelCode=naver
크리드 3 Creed III 2D
11관 CINEMA 11
23:25 25:31 126
144 142 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200411&link_cinemaCode=2004&link_movieCd=19582&link_date=2023-03-04&link_time=23:25&link_channelCode=naver
영웅 영웅 2D
11관 CINEMA 11
21:00 23:10 130
144 133 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200411&link_cinemaCode=2004&link_movieCd=19224&link_date=2023-03-04&link_time=21:00&link_channelCode=naver
다음 소희 NEXT SOHEE 2D
씨네커플 1관 Cine Couple CINEMA 1
21:25 23:53 148
86 83 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200401&link_cinemaCode=2004&link_movieCd=19469&link_date=2023-03-04&link_time=21:25&link_channelCode=naver
우리 사랑이 향기로 남을 때 Love My Scent 2D
4관 CINEMA 4
20:50 22:48 118
157 157 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200404&link_cinemaCode=2004&link_movieCd=19531&link_date=2023-03-04&link_time=20:50&link_channelCode=naver
2023-03-05
스즈메의 문단속 Suzume 2D
5관 CINEMA 5
15:40 17:51 131
262 231 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200405&link_cinemaCode=2004&link_movieCd=19556&link_date=2023-03-05&link_time=15:40&link_channelCode=naver
대외비 The Devil's Deal 2D
4관 CINEMA 4
13:20 15:25 125
157 149 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200404&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=13:20&link_channelCode=naver
대외비 The Devil's Deal 2D
4관 CINEMA 4
15:40 17:45 125
157 148 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200404&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=15:40&link_channelCode=naver
대외비 The Devil's Deal 2D
5관 CINEMA 5
18:05 20:10 125
262 262 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200405&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=18:05&link_channelCode=naver
대외비 The Devil's Deal 2D
5관 CINEMA 5
20:25 22:30 125
262 262 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200405&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=20:25&link_channelCode=naver
대외비 The Devil's Deal 2D
5관 CINEMA 5
22:45 24:50 125
262 262 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200405&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=22:45&link_channelCode=naver
대외비 The Devil's Deal 2D
6관 CINEMA 6
10:10 12:15 125
270 256 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200406&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=10:10&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
11:40 13:45 125
237 235 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=11:40&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
14:00 16:05 125
237 209 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=14:00&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
16:20 18:25 125
237 218 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=16:20&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
18:40 20:45 125
237 229 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=18:40&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
21:00 23:05 125
237 235 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=21:00&link_channelCode=naver
대외비 The Devil's Deal 2D
9관 CINEMA 9
23:20 25:25 125
237 237 http://www.lottecinema.co.kr/NLCHS/ticketing?link_screenId=200409&link_cinemaCode=2004&link_movieCd=19551&link_date=2023-03-05&link_time=23:20&link_channelCode=naver
대외비 The Devil's Deal 2D
6관 CINEMA 6
12:30 14:35 125
CGV
영화 그 이상의 감동. CGV
All --> 15 --> D Day
www.cgv.co.kr
CGV는 iframe 내부 페이지를 크롤링하는 거라 직접 파싱을 해야합니다.
영어 데이터를 찾긴 했는데 굉장히 애로사항이 많습니다...


우측의 영어 스케줄표 링크를 타고 들어가면 한국어로 나옵니다.

영어 예매페이지가 존재하긴 합니다.

해당 차이처럼 특별관 같은 경우 번역된게 없습니다.
관 같은 경우 그냥 CINEMA를 앞에 붙이고 숫자를 뒤로 옮기면 될 것 같습니다.
영화관 영문명이 순서가 달라서 areacode와 theatercode로 매핑을 해줘야 할 것 같습니다..

http://www.cgv.co.kr/reserve/show-times/eng/?areacode=01&theaterCode=0013&date=20230305
http://www.cgv.co.kr/theaters/?areacode=01&theaterCode=0013&date=20230305
영어와 한국어 링크 주소입니다.

영화 제목은 midx로 비교하여 작업해야 하겠습니다.

특별관 중복 이슈에 CINEMA 순서로 정렬해서 넘겨주니 이걸 처리를 어찌해야...
시작 시간으로 처리를 하자니 16:00에 다른 관에서 영화를 상영한다면? 그리고 상단의 영어 시간표는 17관만 있고 PREMIUM의 경우 존재조차 하지 않습니다. 머리가 아프네요...
그냥 단순히 ~관이 존재하면 관을 지우고 앞에 CINEMA를 붙이는 걸로 마무리 하겠습니다.
영어표기는 사실상 보여주기 식인 것 같아 건들수록 끝이 없을 것 같네요.
마감인 경우 a태그가 달리지 않아 마감이나 매진인 경우 크롤링 되지 않습니다. 헌데 DB에서 어떻게 알고 지워줘야 할지가 조금 막막합니다. 처음엔 POST로 API를 가져다 사용하는게 어려웠는데 이젠 단순 페이지 크롤링이 훨씬 힘드네요...
모든 li태그를 가져온 다음 만약 a태그가 NULL이 나온다면 em의 시간을 읽어와 관, 영화명, 시간과 일치하는 시간표를 DB에서 delete 시키면 될 것 같습니다.
웹 주소의 경우 웹은 도로명과 옛날 주소가 구분되어 있지 않습니다.
<strong class="title">서울특별시 용산구 한강로 3가 40-999 HDC아이파크몰 6층<br>서울특별시 용산구 한강대로23길 55, 6층(한강로동)<a href="./?page=location&theaterCode=0013#menu">위치/주차 안내 ></a></strong>
하지만 모바일 주소의 경우 분리되어 있어 모바일 주소로 도로명 주소를 가져옵시다.
https://m.cgv.co.kr/WebAPP/TheaterV4/TheaterDetail.aspx?tc=0013
<li><strong>지번</strong><span>서울특별시 용산구 한강로 3가 40-999 HDC아이파크몰 6층</span></li>
<li><strong>도로명</strong><span class="line">서울특별시 용산구 한강대로23길 55, 6층(한강로동)</span></li>

더빙이라고 되어있는데 자막인 곳도 있나봅니다...? 영화 코드는 동일합니다.
그냥 영어 제목은 다른 시네마에서 가져오고 영화관 이름만 영어로 저장합시다...
2023.02.27 - [Project/ThreeMovie(영화리뷰및예약도우미)] - CGV 영화 시간표 크롤링 및 예약 주소 가져오기 (Kotlin, jsoup)
CGV는 큰 차이가 없어 이전 링크를 확인하시면 됩니다.
코드
fun getCGVDates(theatercode: String): ArrayList<String> {
val url: String =
CGVurl + "/common/showtimes/iframeTheater.aspx?theatercode=${theatercode}"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.referrer(
CGVurl
)
.header(
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
)
.header("Accept-Language", "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7")
.header(
"Cookie",
"ASP.NET_SessionId=test;"
)
val doc = conn.get()
val days = doc.getElementsByClass("day")
var datelist = ArrayList<String>()
for (day in days) {
val href = day.getElementsByTag("a")[0].attr("href")
val pattern: Pattern = Pattern.compile(".*date=([^&]+).*")
val matcher: Matcher = pattern.matcher(href)
if (matcher.find()) {
datelist.add(matcher.group(1))
}
}
return datelist
}
fun getCGVBrchsEN(): HashMap<String, String> {
val url: String =
CGVurl + "/reserve/show-times/eng/"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
val doc = conn.get()
val scripts = doc.select("script")
var theatersData: String = ""
for (script in scripts) {
if (script.data().contains("var theaterJsonData")) {
val pattern: Pattern = Pattern.compile(".*var theaterJsonData = ([^;]*);")
val matcher: Matcher = pattern.matcher(script.data())
if (matcher.find()) {
theatersData = matcher.group(1)
break
}
}
}
val jsonArray = JSONArray(theatersData)
val brchsEN = HashMap<String, String>()
for (i in 0 until jsonArray.length()) {
val theaters = jsonArray.getJSONObject(i)
val areaTheaterList = theaters.optJSONArray("AreaTheaterDetailList")
for (j in 0 until areaTheaterList.length()) {
val theater = areaTheaterList.getJSONObject(j)
val theaterCode = theater.getString("TheaterCode")
val theaterName = theater.getString("TheaterName")
brchsEN[theaterCode] = theaterName
}
}
return brchsEN
}
fun getCGVTheaters(): ArrayList<HashMap<String, String>> {
val url: String =
CGVurl + "/theaters/"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
val doc = conn.get()
val scripts = doc.select("script")
var theatersData: String = ""
for (script in scripts) {
if (script.data().contains("var theaterJsonData")) {
val pattern: Pattern = Pattern.compile(".*var theaterJsonData = ([^;]*);")
val matcher: Matcher = pattern.matcher(script.data())
if (matcher.find()) {
theatersData = matcher.group(1)
break
}
}
}
val jsonArray = JSONArray(theatersData)
val theaterlist = ArrayList<HashMap<String, String>>()
for (i in 0 until jsonArray.length()) {
val theaters = jsonArray.getJSONObject(i)
val areaTheaterList = theaters.optJSONArray("AreaTheaterDetailList")
for (j in 0 until areaTheaterList.length()) {
val theater = areaTheaterList.getJSONObject(j)
val theaterCode = theater.getString("TheaterCode")
val theaterName = theater.getString("TheaterName")
val addr = getCGVAddress(theaterCode)
val city = addr.substring(0..1)
val theatermap = HashMap<String, String>()
theatermap["theaterCode"] = theaterCode
theatermap["brchKR"] = theaterName
theatermap["addr"] = addr
theatermap["city"] = city
theaterlist.add(theatermap)
}
}
return theaterlist
}
fun getCGVAddress(theatercode: String): String {
val url: String =
"https://m.cgv.co.kr/WebApp/TheaterV4/TheaterDetail.aspx?tc=${theatercode}"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
val doc = conn.get()
val addr = doc.getElementsByClass("info_map")[0].getElementsByClass("line")[0].text()
return addr
}
fun chgStrtoDatestr(str: String): String {
return "${str.substring(0..1)}:${str.substring(2..3)}"
}
fun chgScreenKRtoEN(screenKR: String): String {
var screenEN: String = screenKR
if ("관" in screenKR)
screenEN = "CINEMA ${screenEN.replace("관", "")}"
return screenEN
}
fun getCGVShowtimes(theaterlist: ArrayList<HashMap<String, String>>, brchsEN: HashMap<String, String>): Unit {
for (theater in theaterlist) {
val theaterCode = theater["theaterCode"] ?: ""
val brchKR = theater["brchKR"] ?: ""
val brchEN = brchsEN[theaterCode] ?: ""
val addr = theater["addr"] ?: ""
val city = theater["city"] ?: ""
val datelist = getCGVDates(theaterCode)
println("${city} ${brchKR} ${brchEN}\n${addr}")
for (date in datelist) {
println(date)
val url: String =
CGVurl + "/common/showtimes/iframeTheater.aspx?theatercode=${theaterCode}&date=${date}"
val conn = Jsoup.connect(url)
.userAgent(userAgent)
.referrer(
CGVurl
)
.header(
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
)
.header("Accept-Language", "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7")
.header(
"Cookie",
"ASP.NET_SessionId=test;"
)
val doc = conn.get()
val showtimes = doc.getElementsByClass("col-times")
for (showtime in showtimes) {
val infoMovie = showtime.getElementsByClass("info-movie")[0]
val movieName = infoMovie.getElementsByTag("a")[0].text()
val runningTime = infoMovie.getElementsByTag("i")[2].text().replace("분", "")
val typeHalls = showtime.getElementsByClass("type-hall")
for (typeHall in typeHalls) {
val infoHall = typeHall.getElementsByClass("info-hall")[0]
val playKind = infoHall.getElementsByTag("li")[0].text()
val screenKR = infoHall.getElementsByTag("li")[1].text()
val screenEN = chgScreenKRtoEN(screenKR)
val allSeats = infoHall.getElementsByTag("li")[2].text().replace("[^0-9]+".toRegex(), "")
val infoTimeTable = typeHall.getElementsByClass("info-timetable")[0]
val timeinfoes = infoTimeTable.getElementsByTag("li")
for (timeinfo in timeinfoes) {
val datas = timeinfo.getElementsByTag("a")
var starttime = ""
var endtime = ""
var ticketPage = ""
var seatsLeft = ""
if (datas.isEmpty() || datas[0].attr("href") == "/") {
starttime = timeinfo.getElementsByTag("em")[0].text()
seatsLeft = "마감|매진"
} else {
starttime = chgStrtoDatestr(datas[0].attr("data-playstarttime"))
endtime = chgStrtoDatestr(datas[0].attr("data-playendtime"))
ticketPage = CGVurl + datas[0].attr("href")
seatsLeft = datas[0].attr("data-seatremaincnt")
}
println("${movieName} ${playKind}\n${screenKR} ${screenEN}\n${starttime} ${endtime} ${runningTime}\n${allSeats} ${seatsLeft}\n${ticketPage}")
}
}
}
}
}
}
제주 CGV제주노형 CGV Jeju-nohyeong
제주특별자치도 제주시 노형로 407, 노형타워5층
20230306
대외비 2D
1관 CINEMA 1
10:00 12:06 116
178 168
http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230306&THEATER_CD=0259&PLAY_START_TM=1000&AREA_CD=01&SCREEN_CD=001
대외비 2D
1관 CINEMA 1
12:25 14:31 116
178 167
http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230306&THEATER_CD=0259&PLAY_START_TM=1225&AREA_CD=01&SCREEN_CD=001
대외비 2D
1관 CINEMA 1
14:50 16:56 116
178 168
http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230306&THEATER_CD=0259&PLAY_START_TM=1450&AREA_CD=01&SCREEN_CD=001
대외비 2D
1관 CINEMA 1
17:15 19:21 116
178 165
http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230306&THEATER_CD=0259&PLAY_START_TM=1715&AREA_CD=01&SCREEN_CD=001
대외비 2D
1관 CINEMA 1
19:40 21:46 116
178 161
http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230306&THEATER_CD=0259&PLAY_START_TM=1940&AREA_CD=01&SCREEN_CD=001
대외비 2D
1관 CINEMA 1
22:05 24:11 116
178 168
http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230306&THEATER_CD=0259&PLAY_START_TM=2205&AREA_CD=01&SCREEN_CD=001
대외비 2D
6관 CINEMA 6
16:00 18:06 116
106 96
'Project > ThreeMovie(영화리뷰및예약도우미)' 카테고리의 다른 글
| JpaRepository join using QueryProjection with DTO(kotlin) (0) | 2023.03.13 |
|---|---|
| JpaRepository saveAll(Insert) 사용하기 (0) | 2023.03.12 |
| 2023/03/02 회의록 (0) | 2023.03.02 |
| 메가박스(MegaBox) 시간표 가져오기(jsoup, kotlin) (0) | 2023.03.02 |
| 롯데시네마(Lotte Cinema) 시간표 가져오기 (jsoup, kotlin) (1) | 2023.03.02 |
댓글