티스토리 뷰

728x90
반응형

안녕하세요! 이번에는 크롤링 연습 예제로 다음(DAUM)의 "영화순위"를 가져와보려고 합니다!

다음 영화 순위는 최대 TOP 30까지 보여줍니다.

 

각 영화 정보는 크게 [이미지, 제목, 평점, 리뷰수, 예매율, 개봉일자]로 구성됩니다.

이번 포스트에서는 정확히 저렇게 6개 항목을 가져와서 출력해보고,

마지막으로 영화 제목과 순위 그리고 이미지를 파일로 저장해볼 생각입니다.

 

아래 이미지를 보시다시피 한 페이지에 5개의 영화정보가 나오고,

페이지 수는 6개이므로 총 30개의 영화에 대한 순위를 나타냅니다.

 

이제 위 이미지의 빨간 상자로 표시된 부분을 HTML 코드로 분석해보겠습니다.

보시다시피 ol.movie_list 태그 안에 li 태그들이 많이 있습니다.

그리고 li 태그들이 정확히 30개 임은 세워보면 알 수 있습니다.

현재 보여지지 않는 영화 정보는 hide 클래스로 감춰져 있는 것 같습니다.

그렇기 때문에 굳이 페이지를 넘겨서 영화 정보를 확인할 필요는 없어보입니다.

그리고 실제로 2페이지로 넘겨서 봐도 아래와 같이 아까 처음에 있던 5개의 영화정보가 hide 클래스가 추가되었고 그 다음 5개가 hide 클래스가 제거된 것을 확인할 수 있었습니다.

이제 li 태그 한 개의 구성요소들을 살펴봄으로써 영화 정보에 대한 HTML 태그를 확인해보겠습니다.

위 이미지는 색깔별로 정보와 일치하는 HTML 요소들을 표시해놓은 것입니다.

이제 위 분석한 요소대로 파이썬으로 정보를 가져와보도록 하겠습니다.

import requests
from bs4 import BeautifulSoup

url = 'https://search.daum.net/search?nil_suggest=btn&w=tot&DA=SBC&q=%EC%98%81%ED%99%94%EC%88%9C%EC%9C%84'
headers = {
	'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
}

response = requests.get(url, headers=headers)

soup = BeautifulSoup(response.text, 'lxml')

movieInfoList = soup.find('ol', attrs={'class':'movie_list'}).find_all('li')

movieInfo = movieInfoList[0]

movieRank = movieInfo.find('span', attrs={'class':'num_rank01'}).get_text()
movieImg = movieInfo.find('img').attrs.get('src')
movieTitle = movieInfo.find('a', attrs={'class':'tit_main'}).get_text()
movieScore = movieInfo.find('em', attrs={'class':'rate'}).get_text()
movieScoreCnt = movieInfo.find('a', attrs={'class':'link_count'}).get_text()
movieTicketSales = movieInfo.find('dd', attrs={'class':'cont'}).get_text()
movieOpenDate = movieInfo.find_all('dd', attrs={'class':'cont'})[1].get_text().strip()

print(f'순위 : {movieRank}')
print(f'이미지 : {movieImg}')
print(f'제목 : {movieTitle}')
print(f'점수 : {movieScore}')
print(f'평가참여수 : {movieScoreCnt}')
print(f'예매율 : {movieTicketSales}')
print(f'개봉일자 : {movieOpenDate}')

일단 위 코드는 영화정보 한 개만 가져와서 출력하는 코드입니다.

그리고 그 결과는 아래와 같습니다.

순위 : 1위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2F048040828662172ce3a5c00159da1862605b3d01
제목 : 유체이탈자
점수 : 9.2
평가참여수 : 27명 참여
예매율 : 18%
개봉일자 : 2021.11.24.

위와 같이 잘 나오는 것을 확인했기 때문에 이제 모든 영화 정보 30개를 전부 출력해보겠습니다.

import requests
from bs4 import BeautifulSoup

url = 'https://search.daum.net/search?nil_suggest=btn&w=tot&DA=SBC&q=%EC%98%81%ED%99%94%EC%88%9C%EC%9C%84'
headers = {
	'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
}

response = requests.get(url, headers=headers)

soup = BeautifulSoup(response.text, 'lxml')

movieInfoList = soup.find('ol', attrs={'class':'movie_list'}).find_all('li')

for movieInfo in movieInfoList:
	movieRank = movieInfo.find('span', attrs={'class':f'img_number'})
	movieImg = movieInfo.find('img')
	movieTitle = movieInfo.find('a', attrs={'class':'tit_main'})
	movieScore = movieInfo.find('em', attrs={'class':'rate'})
	movieScoreCnt = movieInfo.find('a', attrs={'class':'link_count'})
	ticketSalesAndOpenDate = movieInfo.find_all('dd', attrs={'class':'cont'})
	if len(ticketSalesAndOpenDate) > 1:
		movieTicketSales = ticketSalesAndOpenDate[0]
		movieOpenDate = ticketSalesAndOpenDate[1]
	else: # 개봉일자가 없을 경우
		movieTicketSales = ticketSalesAndOpenDate[0]

	print(f'순위 : {movieRank.get_text() if movieRank else "X"}')
	print('이미지 : {}'.format(movieImg['src'] if movieImg else "X"))
	print(f'제목 : {movieTitle.get_text() if movieTitle else "X"}')
	print(f'점수 : {movieScore.get_text() if movieScore else "X"}')
	print(f'평가참여수 : {movieScoreCnt.get_text() if movieScoreCnt else "X"}')
	print(f'예매율 : {movieTicketSales.get_text() if movieTicketSales else "X"}')
	print(f'개봉일자 : {movieOpenDate.get_text().strip() if movieOpenDate else "X"}')

그리고 위 코드를 실행하면 아래와 같이 나옵니다.

순위 : 1위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2F048040828662172ce3a5c00159da1862605b3d01
제목 : 유체이탈자
점수 : 9.2
평가참여수 : 27명 참여
예매율 : 18%
개봉일자 : 2021.11.24.
순위 : 2위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2F28a2bbf1962b4f0a48c72f49957c5e4604ca9ccc
제목 : 엔칸토: 마법의 세계
점수 : 9.3
평가참여수 : 4명 참여
예매율 : 15.8%
개봉일자 : 2021.11.24.
순위 : 3위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2F44e1336d38ac01853b72f2acdeb5408054a83b12
제목 : 태일이
점수 : 9.6
평가참여수 : 153명 참여
예매율 : 12.5%
개봉일자 : 2021.12.01.
순위 : 4위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2Fa0fcbda650c0e964ac945ebbe38c5ec8d2dc55ff
제목 : 연애 빠진 로맨스
점수 : 7.8
평가참여수 : 10명 참여
예매율 : 10.5%
개봉일자 : 2021.11.24.
... 중략 ...
순위 : 24위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2Ff8d9bbaa79562d6f47e7890b5c7db740cc7e8d23
제목 : 송해 1927
점수 : 9.7
평가참여수 : 21명 참여
예매율 : 0.3%
개봉일자 : 2021.11.18.
순위 : 25위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2Ffdbe9b11274de92532308a40449d9a231dd3b9cf
제목 : 귀멸의 칼날: 남매의 연
점수 : 7.1
평가참여수 : 78명 참여
예매율 : 0.3%
개봉일자 : 2021.11.10.
순위 : 26위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2F5548145a15a57370681229ae9060ab6ee88302b2
제목 : 아네트
점수 : 7.7
평가참여수 : 42명 참여
예매율 : 0.2%
개봉일자 : 2021.10.27.
순위 : 27위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2F6a46dc099e54db896cfcc643290a34e583557fa8
제목 : 로그 인 벨지움
점수 : 
평가참여수 : X
예매율 : 0.2%
개봉일자 : 2021.10.27.
순위 : 28위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2Fa716f8d9423b8c395bca4b3a47f59b031c959ca4
제목 : 악인은 너무 많다 2 - 제주 실종사건의 전말
점수 : 7.0
평가참여수 : 9명 참여
예매율 : 0.2%
개봉일자 : 2021.11.11.
순위 : 29위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fmovie%2F09942553dd9ceff78131298425e36b9a5f23df8e
제목 : 동백
점수 : 9.3
평가참여수 : 27명 참여
예매율 : 0.2%
개봉일자 : 2021.10.21.
순위 : 29위
이미지 : https://search1.kakaocdn.net/thumb/R232x328.q85/?fname=http%3A%2F%2Ft1.daumcdn.net%2Fcfile%2F1741304A508E2D7430
제목 : 호빗: 뜻밖의 여정
점수 : 8.1
평가참여수 : 1,111명 참여
예매율 : 0.2%
개봉일자 : 2021.11.18.

우연하게 29위가 두 개가 나왔습니다. 정말 그런 지 확인해보겠습니다.

다행히 아래 이미지를 보시면 알겠지만 실제 결과에도 29위가 두개였습니다.

다행이네요.

정보 한 개를 출력했을 때와 바로 위에서 사용한 30개의 영화 정보를 가져와서 출력하는 코드에는 몇가지 차이점이 있는데요.

일단 첫번째로 개봉일자가 없는 경우가 존재했습니다. 바로 위 이미지에서도 27위에 해당하는 영화의 정보에는 예매율은 있지만 개봉일자는 없습니다. 이런 경우에 None 값에 .get_text() 를 하게 됨으로 예외처리를 해주어야 합니다.

또한 예매일자와 개봉일자의 경우에는 동일한 HTML 태그와 동일한 Class를 사용하기 때문에 index로 불러와야 했습니다.

이 점을 제외하고는 마지막으로 moveInfoList로부터 받은 배열을 for 반복문을 사용해서 돌렸다는 점의 차이점이 존재합니다.

 

이렇게 다음 사이트에서의 영화 순위를 가져와 봤습니다.

 


 

이제 추가로 영화의 이미지를 파일로 저장하고 파일 이름을 "영화순위-영화제목" 형식으로 설정하도록 해보겠습니다.

import requests
from bs4 import BeautifulSoup

url = 'https://search.daum.net/search?nil_suggest=btn&w=tot&DA=SBC&q=%EC%98%81%ED%99%94%EC%88%9C%EC%9C%84'
headers = {
	'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
}

response = requests.get(url, headers=headers)

soup = BeautifulSoup(response.text, 'lxml')

movieInfoList = soup.find('ol', attrs={'class':'movie_list'}).find_all('li')

for movieInfo in movieInfoList:
	movieRank = movieInfo.find('span', attrs={'class':f'img_number'}).get_text()
	movieImg = movieInfo.find('img')['src']
	movieTitle = movieInfo.find('a', attrs={'class':'tit_main'}).get_text().replace(':', '')

	imgSrc = requests.get(movieImg, headers=headers)
	with open(f'{movieRank}-{movieTitle}.jfif', 'wb') as imgFile:
		imgFile.write(imgSrc.content)

아까 위에서 영화 정보를 출력할 때 사용한 코드를 재활용해서 작성한 코드입니다.

특이한 점으로는 movieTitle 에서 replace(':', '') 를 한 것이 있는데,

이걸 한 이유는 Windows 에서 특수 기호가 들어간 파일 이름을 가진 파일로 파일을 저장할 때

오류가 나서 저장이 되지 않는 문제가 있기 때문에 작성해주었습니다.

 

그리고 이미지 파일의 경우에는 일반적인 text 형식의 파일이 아니라 binary 파일 또는 byte-array 파일이기 때문에 open 함수에서 'wb' 옵션을 사용해주었고, requests.get 함수의 반환 값인 Response 객체에서도 평소에 사용하던 text 가 아닌 content 를 사용해주었습니다.

 

그리고 위 코드를 실행하게 되면 아래와 같이 이미지 파일들을 볼 수 있으며, 방금 지정한 파일이름들로 저장된 것을 확인할 수 있습니다.

이상으로 파이썬으로 다음 영화 순위 TOP 30 까지 영화 정보 가져오기와

파이썬으로 다음 영화 순위 TOP 30 까지 영화 이미지 가져오기를

해보았습니다.

 

- 끝 -

728x90
반응형
댓글