-
인프런 동영상 웹 스크래핑하기 - 3 : 네트워크 분석 - 2개발/웹크롤링 2022. 1. 16. 15:11
사실, 강의 형식으로 준비하려고 했는데, 강의로 하기에는 제 지식도 많지 않고 일일히 다 설명하려면 까마득한데다, 내용이 다 안 담길 거 같아서 코드 리뷰 형식으로 진행하겠습니다...
우선 인프런의 요청을 가로채기 위해서 selenium-wire를 사용했습니다. selenium-wire에서 requests를 받아오는 방법은 다음과 같습니다.
>>> driver.requests [Request(method='POST', url='https://accounts.google.com/ListAccounts?gpsia=1&sour...
비디오가 들어 있는 url 패턴을 가로채서 해당 url에 get 요청을 보낸 후 6초 단위의 동영상 바이트 덩어리를 한 파일에 다 합쳐서 저장할 것입니다. url 패턴 중에서도 비디오의 url 리스트들을 모두 받아낼 수 있는 url이 있습니다. 이를 간단하게 다음과 같이 받아왔습니다.
for request in self._driver.requests: if "https://vod.inflearn.com" in request.url and '.m3u8' in request.url: root_url = request.url[:request.url.rfind('/')] + '/' headers.update(request.headers) resp = requests.get(url=request.url, headers=headers) lines = [line for line in resp.text.strip().split('\n') if '#' not in line] meta_info_url = lines[-1] break
regex를 쓸 수도 있지만 귀찮아서 안 썼습니다. root_url은 지금 보고 있는 영상의 url을 말합니다. headers를 업데이트한 것은 혹시 몰라서 넣어주었습니다. resp.text를 보면 여러 줄에 걸쳐서 동영상의 옵션들에 따른 링크 주소가 담긴 목록을 반환합니다. #으로 시작하는 건 주석인 것 같아서 lines를 받아올 때 생략하고 받았습니다. resp.text의 예시는 다음과 같습니다.
#EXTM3U #EXT-X-VERSION:3 #EXT-X-INDEPENDENT-SEGMENTS #EXT-X-STREAM-INF:BANDWIDTH=788643,AVERAGE-BANDWIDTH=429903,CODECS="avc1.640028,mp4a.40.5",RESOLUTION=960x540,FRAME-RATE=29.970 0f5abd5dd85c257f848ebe8aa983e7792b88f127_Ott_Hls_Ts_Avc_Aac_16x9_960x540p_30Hz_3.5Mbps_qvbr.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=909792,AVERAGE-BANDWIDTH=512858,CODECS="avc1.640028,mp4a.40.5",RESOLUTION=1278x718,FRAME-RATE=29.970 0f5abd5dd85c257f848ebe8aa983e7792b88f127_Ott_Hls_Ts_Avc_Aac_16x9_1280x720p_30Hz_3.5Mbps_qvbr.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=2427362,AVERAGE-BANDWIDTH=1172231,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=29.970 0f5abd5dd85c257f848ebe8aa983e7792b88f127_Ott_Hls_Ts_Avc_Aac_16x9_1920x1080p_30Hz_8.5Mbps_qvbr.m3u8
저는 이 중에서도 가장 화질이 좋은 마지막 url에서 다운로드하고 싶기 때문에, meta_info_url에 lines[-1]을 할당했습니다. 참고로 이 목록 중 첫 번째 url에 get을 보내면 다음과 같은 데이터가 반환됩니다.
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:7 #EXT-X-MEDIA-SEQUENCE:1 #EXT-X-PLAYLIST-TYPE:VOD #EXTINF:6, 0f5abd5dd85c257f848ebe8aa983e7792b88f127_Ott_Hls_Ts_Avc_Aac_16x9_960x540p_30Hz_3.5Mbps_qvbr_00001.ts #EXTINF:6, 0f5abd5dd85c257f848ebe8aa983e7792b88f127_Ott_Hls_Ts_Avc_Aac_16x9_960x540p_30Hz_3.5Mbps_qvbr_00002.ts #EXTINF:6, 0f5abd5dd85c257f848ebe8aa983e7792b88f127_Ott_Hls_Ts_Avc_Aac_16x9_960x540p_30Hz_3.5Mbps_qvbr_00003.ts #EXTINF:6,
이 목록들은 지금 페이지에서 시청 중인 비디오를 6초 단위로 쪼개어서 받아올 수 있는 경로 모음입니다.
이를 응용해서 다음과 같이 코드를 짰습니다.
resp = requests.get(url=(root_url + meta_info_url), headers=headers) if resp.status_code != 200: print(resp.text) return None # get source url list sources = [src for src in resp.text.strip().split('\n') if '#' not in src]
이제 sources에 담긴 url에 요청만 하면 6초 단위의 비디오를 받아올 수 있는 겁니다. 이제 이 6초 단위의 비디오를 videos라는 배열에 담은 후, 파일에 써줍니다. 이 과정은 다음 코드로 구현됩니다.
videos = [] for idx, src in enumerate(sources): print(f'영상 다운로드 중... ({idx / len(sources) * 100:<4.1f}%)', end='\r') resp = requests.get(url=(root_url + src), headers=headers) if resp.status_code == 200: videos.append(resp.content) print('영상 다운로드 완료. 파일로 다운로드합니다.') # 다운로드 받을 장소. src_path = os.path.join(DEST_PATH, lecture_title) if not os.path.isdir(src_path): os.mkdir(src_path) with open(os.path.join(src_path, course_filename), 'wb') as f: for idx, vid in enumerate(videos): print(f'파일 합치는 중... ({idx / len(videos) * 100:<4.1f}%)', end='\r') f.write(vid) print('다운로드 완료.', lecture_title, '-', course_title) videos.clear()
이상으로 인프런의 강의 영상을 하나의 파일로 다운로드 받을 수 있게 되었습니다. 완성된 코드는 깃허브에 올리겠습니다.
'개발 > 웹크롤링' 카테고리의 다른 글
인프런 동영상 웹 스크래핑하기 - 마치며(최종 코드) (1) 2022.01.16 인프런 동영상 웹 스크래핑하기 - 3 : 네트워크 분석 - 1 (1) 2022.01.10 인프런 동영상 웹 스크래핑하기 - 2: 자동로그인 기능 - 2 (0) 2022.01.08 인프런 동영상 웹 스크래핑하기 - 2: 자동로그인 기능 - 1 (1) 2022.01.08 인프런 동영상 웹 스크래핑하기 - 1: 준비 과정 (1) 2022.01.08