CGV 영화 시간표 크롤링 및 예약

CGV

https://www.cgv.co.kr/

극장에 가서 예약 버튼을 눌러 어떻게 진행되는지 봅시다.

어디든 상관없지만 CGV 동창회에서 하겠습니다.


영화 상영시간표는 아래에서 확인하실 수 있습니다.
아무거나 클릭해 봅시다.


http://www.cgv.co.kr/ticket/?MOVIE_CD=20031748&MOVIE_CD_GROUP=20031633&PLAY_YMD=20230207&THEATER_CD=0046&PLAY_START_TM=2250&AREA_CD=13&SCREEN_CD=009


URI를 보면 내가 선택한 극장과 영화에 대한 정보가 GET 방식으로 전달되는 것을 알 수 있다.
한 번 보자.

  • MOVIE_CD
  • MOVIE_CD_GROUP
  • PLAY_YMD
  • 극장_CD
  • PLAY_START_TM
  • AREA_CD
  • 스크린_CD

만들어지는 것을 볼 수 있습니다.

MOVIE_CD는 영화 코드이고, MOVIE_CD_GROUP도 영화를 분류하는 코드입니다.

PLAY_YMD가 예약한 날짜는 언제입니까?

THEATER_CD 및 AREA_CD는 선택한 튜브 필름입니다.

PLAY_START_TM 및 SCREEN_CD는 영화가 언제 선택되고 어느 극장에서 상영될 것인지에 대한 정보를 전달하는 것 같습니다.

저장하거나 분석할 정보가 너무 많으므로 이전 동영상 선택 화면으로 돌아가겠습니다.

http://www.cgv.co.kr/theaters/?areacode=01&theaterCode=0046&date=20230207

THEATERCODE는 동일하지만 AREACODE는 01로 다릅니다.

왜 다를까요…?

소스코드 대신 극장 정보를 보내는 API가 있다면 F12 키를 눌러 사용하시고 NETWORK 탭으로 가셔서 검색하시면 됩니다.

iframe에서 추가 페이지를 여는 중이라 API를 찾을 수 없습니다.

소스 코드로 가서 확인해야 할 것 같습니다.


주소에는 확인하고 있는 예약 주소의 값이 포함되어 있는 것을 볼 수 있습니다.


쿼리에 전달된 날짜 값을 변경하면 날짜도 변경됩니다.
영화관은 보통 주간 편성만 사용하기 때문에 오늘 + 7일까지 날짜를 가져오면 모든 영화 편성표를 불러올 수 있습니다.

저장해야 할 정보를 정리해보자.

  • 시간 – 2월 8일 오후 12시 30분
  • 남은 좌석 수(저장하지 않음), 총 좌석 수
  • 2d, 4dx – 어떤 종류의 영화
  • 5시네마 3시네마 – 영화관마다 상영시간표가 다르고 상영관의 크기가 다르기 때문에 선호하는 상영관이 다를 수 있습니다.
  • 개봉일 – 영화명_출시일(Avatar_2023)로 저장해두었으니 변경해주셔야 합니다.

HTML을 분석해 봅시다.

먼저, 영화 정보는 각 영화에 대한 열 시간으로 나뉩니다.


내부는 유형 홀로 나뉘어 파이프로 별도로 보관됩니다.

  • 시간, 잔여좌석수 – 정보 시간표 > ul > li > a에 data-playstarttime, data-seatremaincnt로 저장됩니다.
  • 영화관 종류 및 홀, 총 좌석수 – 인포홀 > ul > 1차 자식 = 2D, 2차 차일드 = 5홀, 3차 차일드 = 총 좌석 수
  • 개봉일 – 인포필름 > 라스트아이

아래의 다른 영화를 확인하고 패턴이 동일한지 확인해 봅시다.




영화관에서의 시간표 패턴 분석은 끝난 것 같다.

코드로 작성하고 데이터를 가져옵니다.


2023년 2월 27일 CGV 회의 일정입니다.


많은 영화가 있습니다.

jsoup 사용시 common/shottimes/iframeTheater.aspx 에 그냥 접속해서 전달하면 데이터가 안옵니다.

약간의 리퍼러, useragent, 헤더를 추가하면 작동하도록 보안 패치가 적용된 것 같습니다.

override fun getShowTime(movieTheater: String): List<ShowTime> {
		val url: String =
			"http://www.cgv.co.kr/common/showtimes/iframeTheater.aspx?theatercode=0046&date=20230227"
		val conn = Jsoup.connect(url)
			.userAgent(userAgent)
			.referrer(
				"http://www.cgv.co.kr/theaters/"
			)
			.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")

		println(showtimes.size)
		for (showtime in showtimes) {
			val infoMovie = showtime.getElementsByClass("info-movie")
			val movieName = infoMovie(0).getElementsByTag("a")(0).text()
			val age = infoMovie(0).getElementsByTag("i")(0).text()
			val categories = infoMovie(0).getElementsByTag("i")(1).text()
			val runningTime = infoMovie(0).getElementsByTag("i")(2).text()
			val comeOut = infoMovie(0).getElementsByTag("i")(3).text().replace("(^0-9)+".toRegex(), "")

			println("${movieName} ${age} ${categories} ${runningTime} ${comeOut}")
		}




		return emptyList()
	}


영화 정보 좋네요.

이제 각 영화에 대한 극장 및 상영 정보를 알아봅시다.

override fun getShowTime(movieTheater: String): List<ShowTime> {
		val url: String =
			"http://www.cgv.co.kr/common/showtimes/iframeTheater.aspx?theatercode=0046&date=20230227"
		val conn = Jsoup.connect(url)
			.userAgent(userAgent)
			.referrer(
				"http://www.cgv.co.kr/theaters/"
			)
			.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")

		println(showtimes.size)
		for (showtime in showtimes) {
			val infoMovie = showtime.getElementsByClass("info-movie")(0)
			val movieName = infoMovie.getElementsByTag("a")(0).text()
			val age = infoMovie.getElementsByTag("i")(0).text()
			val categories = infoMovie.getElementsByTag("i")(1).text()
			val runningTime = infoMovie.getElementsByTag("i")(2).text()
			val comeOut = infoMovie.getElementsByTag("i")(3).text().replace("(^0-9)+".toRegex(), "")

			println("${movieName} ${age} ${categories} ${runningTime} ${comeOut}")

			val typeHalls = showtime.getElementsByClass("type-hall")
			for (typeHall in typeHalls) {
				val infoHall = typeHall.getElementsByClass("info-hall")(0)
				val dimension = infoHall.getElementsByTag("li")(0).text()
				val whereTheater = infoHall.getElementsByTag("li")(1).text()
				val allSeats = infoHall.getElementsByTag("li")(2).text().replace("(^0-9)+".toRegex(), "")

				println("${dimension} ${whereTheater} ${allSeats}")

				val infoTimeTable = typeHall.getElementsByClass("info-timetable")(0)
				val timeinfoes = infoTimeTable.getElementsByTag("li")

				for (timeinfo in timeinfoes) {
					val datas = timeinfo.getElementsByTag("a")(0)
					val starttime = datas.attr("data-playstarttime")
					val href = CGVurl + datas.attr("href")
					val seatsLeft = datas.attr("data-seatremaincnt")

					println("${starttime} ${href} ${seatsLeft}")
				}
			}
		}

		return emptyList()
	}


데이터가 정렬되고 잘 흐릅니다.

하지만 남은 일정이 모두 마감되면 날이 없다.
오류를 별도로 처리해 보겠습니다.

	for (timeinfo in timeinfoes) {
			val datas = timeinfo.getElementsByTag("a")
			var starttime = ""
			var href = ""
			var seatsLeft = ""
            if (datas.isEmpty()) {
                starttime = timeinfo.getElementsByTag("em")(0).text().replace(":", "")
                seatsLeft = "마감"
            } else {
                starttime = datas(0).attr("data-playstarttime")
                href = CGVurl + datas(0).attr("href")
                seatsLeft = datas(0).attr("data-seatremaincnt")
            }


            println("${movieName} ${age}세 ${categories} ${runningTime}분 ${comeOut} ${dimension} ${whereTheater} ${allSeats} ${starttime} ${href} ${seatsLeft}좌석 남음")
        }

이제 모든 극장과 모든 날짜에 대한 데이터가 필요하므로 가져오겠습니다.

먼저 영화관(CGV상봉, CGV강남)과 같은 데이터를 얻어보자.


sect-city 아래에 li 태그로 구분되어 감싸져 있으며, area는 area 클래스 바로 아래의 a 태그 안에 있다.
그러나 페이지를 요청하면 코드에 포함되지 않습니다.

요청한 페이지를 보니 거기에 하드코딩을 해서 데이터가 있는 듯…?


아무리 찾아봐도 안나와서 리유니온으로 검색했더니 스크립트에 TheaterJsonData가 있더군요… 거기에서 데이터를 가져와야 할 것 같네요…

데이터는

		val url: String =
			"http://www.cgv.co.kr/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
				}
			}
		}

당신은 그것을 뽑을 수 있습니다

({"AreaTheaterDetailList":({"RegionCode":"01","TheaterCode":"0056","TheaterName":"CGV강남","TheaterName_ENG":null,"IsSelected":true},{"RegionCode":"01","TheaterCode":"0001","TheaterName":"CGV강변","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0229","TheaterName":"CGV건대입구","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0010","TheaterName":"CGV구로","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0063","TheaterName":"CGV대학로","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0252","TheaterName":"CGV동대문","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0230","TheaterName":"CGV등촌","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0009","TheaterName":"CGV명동","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0105","TheaterName":"CGV명동역 씨네라이브러리","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0057","TheaterName":"CGV미아","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0288","TheaterName":"CGV방학","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0030","TheaterName":"CGV불광","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0046","TheaterName":"CGV상봉","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0300","TheaterName":"CGV성신여대입구","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0088","TheaterName":"CGV송파","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0276","TheaterName":"CGV수유","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0150","TheaterName":"CGV신촌아트레온","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0040","TheaterName":"CGV압구정","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0112","TheaterName":"CGV여의도","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0292","TheaterName":"CGV연남","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0059","TheaterName":"CGV영등포","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0074","TheaterName":"CGV왕십리","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0013","TheaterName":"CGV용산아이파크몰","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0131","TheaterName":"CGV중계","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0199","TheaterName":"CGV천호","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0107","TheaterName":"CGV청담씨네시티","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0223","TheaterName":"CGV피카디리1958","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0164","TheaterName":"CGV하계","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"0191","TheaterName":"CGV홍대","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"P001","TheaterName":"CINE de CHEF 압구정","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"01","TheaterCode":"P013","TheaterName":"CINE de CHEF 용산아이파크몰","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"01","RegionName":"서울","RegionName_ENG":"Seoul","DisplayOrder":"1","IsSelected":true},{"AreaTheaterDetailList":({"RegionCode":"02","TheaterCode":"0260","TheaterName":"CGV경기광주","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0255","TheaterName":"CGV고양행신","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0257","TheaterName":"CGV광교","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0266","TheaterName":"CGV광교상현","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0348","TheaterName":"CGV광명역","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0232","TheaterName":"CGV구리","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0344","TheaterName":"CGV기흥","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0278","TheaterName":"CGV김포","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0188","TheaterName":"CGV김포운양","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0298","TheaterName":"CGV김포한강","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0351","TheaterName":"CGV다산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0124","TheaterName":"CGV동백","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0041","TheaterName":"CGV동수원","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0106","TheaterName":"CGV동탄","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0265","TheaterName":"CGV동탄역","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0233","TheaterName":"CGV동탄호수공원","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0226","TheaterName":"CGV배곧","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0155","TheaterName":"CGV범계","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0015","TheaterName":"CGV부천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0194","TheaterName":"CGV부천역","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0287","TheaterName":"CGV부천옥길","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0049","TheaterName":"CGV북수원","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0242","TheaterName":"CGV산본","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0196","TheaterName":"CGV서현","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0304","TheaterName":"CGV성남모란","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0143","TheaterName":"CGV소풍","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0012","TheaterName":"CGV수원","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0274","TheaterName":"CGV스타필드시티위례","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0073","TheaterName":"CGV시흥","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0211","TheaterName":"CGV안산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0279","TheaterName":"CGV안성","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0003","TheaterName":"CGV야탑","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0262","TheaterName":"CGV양주옥정","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0338","TheaterName":"CGV역곡","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0004","TheaterName":"CGV오리","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0305","TheaterName":"CGV오산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0307","TheaterName":"CGV오산중앙","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0271","TheaterName":"CGV용인","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0113","TheaterName":"CGV의정부","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0187","TheaterName":"CGV의정부태흥","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0205","TheaterName":"CGV이천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0054","TheaterName":"CGV일산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0320","TheaterName":"CGV정왕","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0055","TheaterName":"CGV죽전(리뉴얼중)","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0148","TheaterName":"CGV파주문산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0310","TheaterName":"CGV파주야당","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0181","TheaterName":"CGV판교","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0195","TheaterName":"CGV평촌","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0052","TheaterName":"CGV평택","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0334","TheaterName":"CGV평택고덕","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0214","TheaterName":"CGV평택소사","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0309","TheaterName":"CGV포천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0326","TheaterName":"CGV하남미사","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0301","TheaterName":"CGV화성봉담","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0145","TheaterName":"CGV화정","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0342","TheaterName":"DRIVE IN 곤지암(임시휴업)","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"02","TheaterCode":"0365","TheaterName":"DRIVE IN 용인크랙사이드","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"02","RegionName":"경기","RegionName_ENG":"Gyeonggi","DisplayOrder":"2","IsSelected":false},{"AreaTheaterDetailList":({"RegionCode":"202","TheaterCode":"0043","TheaterName":"CGV계양","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0198","TheaterName":"CGV남주안","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0021","TheaterName":"CGV부평","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0325","TheaterName":"CGV송도타임스페이스","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0247","TheaterName":"CGV연수역","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0002","TheaterName":"CGV인천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0254","TheaterName":"CGV인천논현","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0340","TheaterName":"CGV인천도화","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0352","TheaterName":"CGV인천시민공원","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0258","TheaterName":"CGV인천연수","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0269","TheaterName":"CGV인천학익","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0308","TheaterName":"CGV주안역","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"202","TheaterCode":"0235","TheaterName":"CGV청라","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"202","RegionName":"인천","RegionName_ENG":"Incheon","DisplayOrder":"3","IsSelected":false},{"AreaTheaterDetailList":({"RegionCode":"12","TheaterCode":"0139","TheaterName":"CGV강릉","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"12","TheaterCode":"0144","TheaterName":"CGV원주","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"12","TheaterCode":"0354","TheaterName":"CGV원통","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"12","TheaterCode":"0281","TheaterName":"CGV인제","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"12","TheaterCode":"0070","TheaterName":"CGV춘천","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"12","RegionName":"강원","RegionName_ENG":"Kangwon","DisplayOrder":"4","IsSelected":false},{"AreaTheaterDetailList":({"RegionCode":"205","TheaterCode":"0261","TheaterName":"CGV논산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0207","TheaterName":"CGV당진","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"03","TheaterCode":"0007","TheaterName":"CGV대전","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"03","TheaterCode":"0286","TheaterName":"CGV대전가수원","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"03","TheaterCode":"0154","TheaterName":"CGV대전가오","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"03","TheaterCode":"0202","TheaterName":"CGV대전탄방","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"03","TheaterCode":"0127","TheaterName":"CGV대전터미널","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0091","TheaterName":"CGV서산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0219","TheaterName":"CGV세종","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0356","TheaterName":"CGV아산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"03","TheaterCode":"0206","TheaterName":"CGV유성노은","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0331","TheaterName":"CGV제천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0044","TheaterName":"CGV천안","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0332","TheaterName":"CGV천안시청","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0293","TheaterName":"CGV천안터미널","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0110","TheaterName":"CGV천안펜타포트","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0228","TheaterName":"CGV청주(서문)","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0297","TheaterName":"CGV청주성안길","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0282","TheaterName":"CGV청주율량","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0142","TheaterName":"CGV청주지웰시티","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0319","TheaterName":"CGV청주터미널","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0284","TheaterName":"CGV충북혁신","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0328","TheaterName":"CGV충주교현","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"205","TheaterCode":"0217","TheaterName":"CGV홍성","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"03,205","RegionName":"대전/충청","RegionName_ENG":"Daejeon/Chungcheong","DisplayOrder":"5","IsSelected":false},{"AreaTheaterDetailList":({"RegionCode":"11","TheaterCode":"0345","TheaterName":"CGV대구","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"11","TheaterCode":"0157","TheaterName":"CGV대구수성","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"11","TheaterCode":"0108","TheaterName":"CGV대구스타디움","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"11","TheaterCode":"0185","TheaterName":"CGV대구아카데미","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"11","TheaterCode":"0343","TheaterName":"CGV대구연경","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"11","TheaterCode":"0216","TheaterName":"CGV대구월성","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"11","TheaterCode":"0147","TheaterName":"CGV대구한일","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"11","TheaterCode":"0109","TheaterName":"CGV대구현대","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"11","RegionName":"대구","RegionName_ENG":"Daegu","DisplayOrder":"6","IsSelected":false},{"AreaTheaterDetailList":({"RegionCode":"05","TheaterCode":"0061","TheaterName":"CGV대연","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0042","TheaterName":"CGV동래","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0337","TheaterName":"CGV부산명지","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0005","TheaterName":"CGV서면","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0285","TheaterName":"CGV서면삼정타워","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0303","TheaterName":"CGV서면상상마당","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0089","TheaterName":"CGV센텀시티","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0160","TheaterName":"CGV아시아드","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"207","TheaterCode":"0335","TheaterName":"CGV울산동구","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"207","TheaterCode":"0128","TheaterName":"CGV울산삼산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"207","TheaterCode":"0264","TheaterName":"CGV울산신천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"207","TheaterCode":"0246","TheaterName":"CGV울산진장","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0306","TheaterName":"CGV정관","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0245","TheaterName":"CGV하단아트몰링","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0318","TheaterName":"CGV해운대","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"0159","TheaterName":"CGV화명","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"05","TheaterCode":"P004","TheaterName":"CINE de CHEF 센텀","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"05,207","RegionName":"부산/울산","RegionName_ENG":"Busan/Ulsan","DisplayOrder":"7","IsSelected":false},{"AreaTheaterDetailList":({"RegionCode":"204","TheaterCode":"0263","TheaterName":"CGV거제","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0330","TheaterName":"CGV경산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0323","TheaterName":"CGV고성","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0053","TheaterName":"CGV구미","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0240","TheaterName":"CGV김천율곡","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0028","TheaterName":"CGV김해","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0311","TheaterName":"CGV김해율하","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0239","TheaterName":"CGV김해장유","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0033","TheaterName":"CGV마산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0097","TheaterName":"CGV북포항","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0272","TheaterName":"CGV안동","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0234","TheaterName":"CGV양산삼호","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0324","TheaterName":"CGV진주혁신","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0023","TheaterName":"CGV창원","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0079","TheaterName":"CGV창원더시티","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0283","TheaterName":"CGV창원상남","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"204","TheaterCode":"0156","TheaterName":"CGV통영","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"204","RegionName":"경상","RegionName_ENG":"Gyeongsang","DisplayOrder":"8","IsSelected":false},{"AreaTheaterDetailList":({"RegionCode":"04","TheaterCode":"0220","TheaterName":"CGV광양","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0221","TheaterName":"CGV광양 엘에프스퀘어","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"206","TheaterCode":"0295","TheaterName":"CGV광주금남로","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"206","TheaterCode":"0193","TheaterName":"CGV광주상무","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"206","TheaterCode":"0210","TheaterName":"CGV광주용봉","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"206","TheaterCode":"0218","TheaterName":"CGV광주첨단","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"206","TheaterCode":"0244","TheaterName":"CGV광주충장로","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"206","TheaterCode":"0090","TheaterName":"CGV광주터미널","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"206","TheaterCode":"0215","TheaterName":"CGV광주하남","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0277","TheaterName":"CGV군산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0237","TheaterName":"CGV나주","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0289","TheaterName":"CGV목포","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0280","TheaterName":"CGV목포평화광장","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0225","TheaterName":"CGV서전주","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0114","TheaterName":"CGV순천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0268","TheaterName":"CGV순천신대","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0315","TheaterName":"CGV여수웅천","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0020","TheaterName":"CGV익산","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0213","TheaterName":"CGV전주고사","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0336","TheaterName":"CGV전주에코시티","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0179","TheaterName":"CGV전주효자","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"04","TheaterCode":"0186","TheaterName":"CGV정읍","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"06","TheaterCode":"0302","TheaterName":"CGV제주","TheaterName_ENG":null,"IsSelected":false},{"RegionCode":"06","TheaterCode":"0259","TheaterName":"CGV제주노형","TheaterName_ENG":null,"IsSelected":false}),"RegionCode":"206,04,06","RegionName":"광주/전라/제주","RegionName_ENG":"Gwangju/Jeonlla/Jeju","DisplayOrder":"9","IsSelected":false})

각 영역은 “AreaTheaterDetailList”(cgv 목록)로 그룹화되며 지역 이름 및 지역 코드와 동일하게 구성됩니다.

json을 구문 분석하기 위해 build.gradle에 종속성을 추가해 보겠습니다.

implementation("org.json:json:20220924")

ClassNotFoundException이 발생하면 서버 전원을 껐다가 켭니다.

저장할 때 자동 컴파일 옵션을 사용하고 있었는데 이 오류가 발생했습니다.

정확한 구분을 살펴보자.

“AreaTheaterDetailList” :(RegionCode: 문자열, TheatreCode: 문자열, TheatreName: 문자열, TheaterName_ENG: 문자열, IsSelected: 부울), RegionCode: 문자열, RegionName: 문자열, RegionName_ENG: 문자열, DisplayOrder: 문자열, IsSelected: 부울

의 형태로 구성되어 있습니다.

필요한 것은 TheaterCode, TheaterName 및 RegionName뿐입니다.

강원이 제일 짧아서 강원으로 테스트 해봅니다.

val jsonArray = JSONArray(theatersData)

		for (i in 0 until jsonArray.length()) {
			val theaters = jsonArray.getJSONObject(i)
			println(theaters)
		}
{"DisplayOrder":"4","RegionCode":"12","AreaTheaterDetailList":({"RegionCode":"12","TheaterName":"CGV강릉","TheaterName_ENG":null,"IsSelected":false,"TheaterCode":"0139"},{"RegionCode":"12","TheaterName":"CGV기린","TheaterName_ENG":null,"IsSelected":false,"TheaterCode":"0355"},{"RegionCode":"12","TheaterName":"CGV원주","TheaterName_ENG":null,"IsSelected":false,"TheaterCode":"0144"},{"RegionCode":"12","TheaterName":"CGV원통","TheaterName_ENG":null,"IsSelected":false,"TheaterCode":"0354"},{"RegionCode":"12","TheaterName":"CGV인제","TheaterName_ENG":null,"IsSelected":false,"TheaterCode":"0281"},{"RegionCode":"12","TheaterName":"CGV춘천","TheaterName_ENG":null,"IsSelected":false,"TheaterCode":"0070"}),"RegionName":"강원","RegionName_ENG":"Kangwon","IsSelected":false}

지역별로 분류해두었기 때문에 필요한 데이터만 분석합니다.

	val jsonArray = JSONArray(theatersData)

		for (i in 0 until jsonArray.length()) {
			val theaters = jsonArray.getJSONObject(i)
			val regionName = theaters.getString("RegionName")
			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")

				println("${regionName} ${theaterName} ${theaterCode}")
			}
		}



모든 영화 정보도 구문 분석하여 가져왔습니다.
이제 마지막 날짜 데이터를 가져옵니다.

날짜 데이터는 분명히 앞서 얻은 common/shottimes/iframeTheater.aspx를 사용하여 검색해야 합니다.

모든 영화 관련 데이터는 이 페이지에서 관리되며 메인 페이지에는 포함되지 않습니다…

미리 알았다면 날짜 데이터도 가져왔을 텐데.


날짜는 찾기가 매우 쉬운 것 같습니다.
모두 div class=”day”에 연결되어 있습니다.
가져온 후 href를 가져와 그대로 사용하거나 날짜를 별도로 가져올 수 있습니다.

먼저 href에서 날짜를 뺍니다.
어쩌면 나는 href를 가져 와서 사용하게 될 것입니다.

		val url: String =
			"http://www.cgv.co.kr/common/showtimes/iframeTheater.aspx?theatercode=0046&date=20230227"
		val conn = Jsoup.connect(url)
			.userAgent(userAgent)
			.referrer(
				"http://www.cgv.co.kr/theaters/"
			)
			.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")
		println(days)



보통 3월 10일쯤 들어왔으니 그냥 분석해보자.

앞에서 사용한 패턴과 매처로 분석해 봅시다.

		val url: String =
			"http://www.cgv.co.kr/common/showtimes/iframeTheater.aspx?theatercode=0046"
		val conn = Jsoup.connect(url)
			.userAgent(userAgent)
			.referrer(
				"http://www.cgv.co.kr/theaters/"
			)
			.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 date: 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()) {
				date = matcher.group(1)
				println(date)
			}
		}



이 영화관의 모든 약속 목록이 있습니다.

그래서 그것을 모아서 계속 진행합시다.

진행 순서는 다음과 같습니다.

  1. 영화관 목록을 가져옵니다.
    (데이터베이스에 저장 후 추후 데이터베이스에서 불러올 예정)
  2. 극장 코드를 URL에 전달한 후 기존 날짜 목록을 가져옵니다.
  3. 극장 코드와 날짜로 이 극장과 이 날짜에 대한 모든 일정을 얻습니다.
class ShowTimeServiceImpl(
	val showTimeRepositorySupport: ShowTimeRepositorySupport
) : ShowTimeService {
	val userAgent: String =
		"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
	val CGVurl = "http://www.cgv.co.kr"
	override fun getShowTime(movieTheater: String): List<ShowTime> {
		val theaterlist = getCGVTheaterData()
		getCGVShowingTime(theaterlist)

		return emptyList()
	}

	fun getCGVDateList(theatercode: String): ArrayList<String> {
		val url: String =
			"http://www.cgv.co.kr/common/showtimes/iframeTheater.aspx?theatercode=${theatercode}"
		val conn = Jsoup.connect(url)
			.userAgent(userAgent)
			.referrer(
				"http://www.cgv.co.kr/theaters/"
			)
			.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 getCGVTheaterData(): ArrayList<Triple<String, String, String>> {
		val url: String =
			"http://www.cgv.co.kr/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<Triple<String, String, String>>()

		for (i in 0 until jsonArray.length()) {
			val theaters = jsonArray.getJSONObject(i)
			val regionName = theaters.getString("RegionName")
			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")

				theaterlist.add(Triple(regionName, theaterCode, theaterName))
			}
		}

		return theaterlist
	}

	fun getCGVShowingTime(theaterlist: ArrayList<Triple<String, String, String>>): Unit {
		for (theater in theaterlist) {
			val datelist = getCGVDateList(theater.second)
			for (date in datelist) {
				println("${theater.first} ${theater.third} ${date}")
				val url: String =
					"http://www.cgv.co.kr/common/showtimes/iframeTheater.aspx?theatercode=${theater.second}&date=${date}"
				val conn = Jsoup.connect(url)
					.userAgent(userAgent)
					.referrer(
						"http://www.cgv.co.kr/theaters/"
					)
					.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 age = infoMovie.getElementsByTag("i")(0).text()
					val categories = infoMovie.getElementsByTag("i")(1).text()
					val runningTime = infoMovie.getElementsByTag("i")(2).text()
					val comeOut = infoMovie.getElementsByTag("i")(3).text().replace("(^0-9)+".toRegex(), "")


					val typeHalls = showtime.getElementsByClass("type-hall")
					for (typeHall in typeHalls) {
						val infoHall = typeHall.getElementsByClass("info-hall")(0)
						val dimension = infoHall.getElementsByTag("li")(0).text()
						val whereTheater = infoHall.getElementsByTag("li")(1).text()
						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 href = ""
							var seatsLeft = ""
							if (datas.isEmpty()) {
								starttime = timeinfo.getElementsByTag("em")(0).text().replace(":", "")
								seatsLeft = "마감"
							} else {
								starttime = datas(0).attr("data-playstarttime")
								href = CGVurl + datas(0).attr("href")
								seatsLeft = datas(0).attr("data-seatremaincnt")
							}


							println("${movieName} ${age}세 ${categories} ${runningTime}분 ${comeOut} ${dimension} ${whereTheater} ${allSeats} ${starttime} ${href} ${seatsLeft}좌석 남음")
						}
					}
				}
			}
		}

	}

	fun getShowingTime(movieTheater: String): List<ShowTime> = showTimeRepositorySupport.getShowTime(movieTheater)
}

자료가 너무 많아서 잘려서 마지막으로 남은 CGV제주노형만 보여드리겠습니다.


광주/전라/제주 CGV제주노형 20230305
대외비 15세 범죄, 드라마 116분분 20230301 2D 1관 178 0900 http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230305&THEATER_CD=0259&PLAY_START_TM=0900&AREA_CD=01&SCREEN_CD=001 168좌석 남음
대외비 15세 범죄, 드라마 116분분 20230301 2D 1관 178 1130 http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230305&THEATER_CD=0259&PLAY_START_TM=1130&AREA_CD=01&SCREEN_CD=001 168좌석 남음
대외비 15세 범죄, 드라마 116분분 20230301 2D 1관 178 1400 http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230305&THEATER_CD=0259&PLAY_START_TM=1400&AREA_CD=01&SCREEN_CD=001 162좌석 남음
대외비 15세 범죄, 드라마 116분분 20230301 2D 1관 178 1630 http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230305&THEATER_CD=0259&PLAY_START_TM=1630&AREA_CD=01&SCREEN_CD=001 168좌석 남음
대외비 15세 범죄, 드라마 116분분 20230301 2D 1관 178 1900 http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230305&THEATER_CD=0259&PLAY_START_TM=1900&AREA_CD=01&SCREEN_CD=001 166좌석 남음
대외비 15세 범죄, 드라마 116분분 20230301 2D 1관 178 2130 http://www.cgv.co.kr/ticket/?MOVIE_CD=20031944&MOVIE_CD_GROUP=20031944&PLAY_YMD=20230305&THEATER_CD=0259&PLAY_START_TM=2130&AREA_CD=01&SCREEN_CD=001 158좌석 남음

로그 첨부합니다…


영화관 주소가 필요한 경우


극장 주소(theaterCode가 쿼리로 전달되어야 함)에 연결하면 극장 정보 제목에 포함됩니다.