1. 동적 크롤링을 활용하여 이미지 데이터 추출하기
오늘은 동적 크롤링을 이용하여 구글 상의 이미지를 다운로드하는 코드를 작성하였다.
늘 그렇듯 사용할 라이브러리 먼저 호출한다.
1-1. 라이브러리 호출
# 1. 필요 모듈 임포트
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import urllib.request
import time
import os
오늘 진행한 수업은 BeautifulSoup 라이브러리를 사용하지 않고, 오로지 selenium 라이브러리를 사용한다. 지난 게시물의 코드와 다른 점은 Keys 모듈을 호출했다는 점이다. 지금까지 상호작용을 위해서는 .click()메서드도 있었지만 키보드의 입력을 구현하는 Keys 모듈을 사용한다. 다음으로 os 모듈을 호출한 이유는 새로운 파일을 만들기 위해서 윈도우 명령어를 사용하기 위함이다. 모듈에 관한 설명은 여기까지하고, 폴더를 생성하는 함수 먼저 살펴보자.
1-2. 폴더 생성 함수 선언
def createFolder(directory):
try:
if not os.path.exists(directory):
os.makedirs(directory)
except Exception as e:
print('Error: creating directory', directory)
print(e)
createFolder함수는 말 그래로 새로운 폴더를 생성한다. 만약 같은 경로 상에 존재하지 않는 경우에만 새로운 폴더를 생성하게 한다. 만약 도중 오류가 발생하면 예외 처리로 오류 내용을 출력한다. 이렇게 운영체제를 수정하거나, 운영체제에 쓰고, 지울 때 os 모듈을 사용하게 된다.
1-3. 키워드 지정 및 폴더 생성 함수 호출, 크롤링 환경 설정
# 3. 키워드 입력 및 폴더 생성
keyword = '꽃'
createFolder('./' + keyword + '_img_download')
print('1. 키워드 설정 및 폴더 생성 완료...')
options = webdriver.ChromeOptions()
options.add_argument('--no-sendbox') #보안 기능인 샌드박스를 비활성화 하겠다는 코드
options.add_argument('--disable-dev-shm-usage') # dev/shm 디렉토리 사용 X
service = ChromeService(executable_path = ChromeDriverManager().install())
driver = webdriver.Chrome(service = service, options = options)
구글에서 찾고자 하는 키워드를 지정해주고, 해당 키워드를 이름으로 삼는 폴더를 하나 생성할 수 있도록 해준다. 위에서 함수를 선언할 때 매개변수로 파일 경로를 넘겨주게 설정했다. 그렇기 때문에 문자열의 연산으로 키워드를 포함하는 경로를 만들어 넘겨주는 것이다.
이후 크롤링을 위한 보안 옵션 해제, 크롬 버전 설정 등을 해준다.
1-4. 키워드를 이용한 검색 후 스크롤 내리기
# 4. 키워드 검색
print('2. 키워드 검색: ' + keyword)
driver.get('https://www.google.co.kr/imghp?hl=ko')
# 검색창에 키워드 입력 -> 입력 태그의 name 속성을 이용하여 요소 검색
# 구글 이미지 검색 textarea name = 'q'
input_keyword = driver.find_element(By.NAME, 'q')
input_keyword.send_keys(keyword)
# 검색(Enter) 키 전송
input_keyword.send_keys(Keys.RETURN)
# 5. 스크롤 내리기
SCROLL_PAUSE_TIME = 3
last_height = driver.execute_script('return document.body.scrollHeight')
# 스크롤하는 기준은 사이트마다 다르기 때문에 document.' ... '.scrollHeight 내부 값들이 변경되게 된다.
이번에 크롤링을 진행하는 사이트는 구글 이미지이다. 구글 이미지에서 사진을 검색하는 방법에는 검색창에 키워드를 입력하고, 검색 버튼을 클릭하는 순서로 이루어진다. 그렇기 때문에 textarea 태그의 name속성을 이용하여 검색을 한다. send_keys메서드를 이용하여 검색하고자 하는 단어를 입력창에 입력한다. 키워드를 입력창에 입력 했으니 이제 검색 버튼을 눌러 검색을 진행한다. 우리가 보통 크롬에서 검색을 하기 위해 검색버튼을 누르기도 하지만, 엔터키를 눌러 검색을 하게 된다. input_keyword.send_keys(Keys.RETURN) 이 코드가 해당 기능을 수행한다.
이제 스크롤을 내려 이미지가 로딩되도록 해준다. excute_script를 통해 자바스크립트 코드를 실행시켜준다. 이 기능은 유튜브 댓글을 추출하는 저저번 게시물에서 다루어보았기 때문에 그것과 비교를 해보면 return document.내용.scrollHeight 사이에 내용 부분이 사이트마다 다르기 때문에 이 부분을 항상 수정해주어야 한다.
1-5. 가장 최하단까지 스크롤
while True:
print('스크롤 중...', keyword)
driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
# 스크롤을 최대한 내리기
time.sleep(SCROLL_PAUSE_TIME)
new_height = driver.execute_script('return document.body.scrollHeight')
if new_height == last_height:
break
last_height = new_height
time.sleep(SCROLL_PAUSE_TIME)
로딩이 되다가, 더 이상 로딩이 되지 않을 때까지 스크롤을 내려야하므로 무한 루프 문을 사용한다. 위에서 sleep의 상수를 정해놓았기 때문에 SCROLL_PAUSE_TIME을 설정해주어 비 정상 접근이 아니라고 인식하게 해야한다. 혹여 비정상 접근이라고 판단되면 IP 접속 정지를 당할 수 있기 때문이다. 그렇게 가장 마지막 부분이 올때까지 스크롤을 내린다.
1-6. 이미지 구분
# 6. 이미지 검색 개수 확인 및 다운로드
links, images = [], []
div = driver.find_elements(By.CLASS_NAME, 'H8Rx8c')
for i in div:
img_tag = i.find_element(By.CLASS_NAME, 'YQ4gaf')
images.append(img_tag)
print('4. 이미지 개수 확인...')
for image in images:
if image.get_attribute('src') != None: # 링크가 존재하지 않는 사진이 존재할 수 있음
links.append(image.get_attribute('src'))
print(keyword, '찾은 이미지 개수', len(links))
time.sleep(SCROLL_PAUSE_TIME)
이제 실질적으로 이미지를 다운 받는 코드를 작성해본다. 여기서 주의할 점은 찾고자 하는 이미지와 링크 아이콘의 클래스 속성이 같기 때문에 먼저 div를 정의해 줌으로써 아이콘과 사진을 분류해준다. 이제 for문을 통해 이미지를 다운 받을 건데 보통 구글에서 검색한 후 표시되는 사진들은 모두 구글 데이터베이스에 존재하는 것이 아닌 이미지의 출처를 남기는 경우가 많다. 그렇기 때문에 src 속성을 가져와 links 리스트에 추가해준다. 링크가 존재하지 않는 동영상, 대표적으로 유튜브의 썸네일과 같은 사진은 링크가 존재하지 않기 때문에 그러한 이미지들은 걸러야한다.
1-7. 이미지 저장
for i,v in enumerate(links): #열거형을 사용하여 인덱스 값과 value 값을 가져옴.
try:
url = v
start = time.time()
# 특정 페이지로 이동해서,
urllib.request.urlretrieve(url, './' + keyword + '_img_download/' + keyword + '_' + str(i+1) +'.jpg')
print(i+1, '/', len(links), keyword, '다운로드... Download time : ', str(time.time() - start)[:5], '초')
except Exception as e:
print(i+1, '/', len(links), keyword, '다운로드 실패..') # 1 / 980 진행률 표시
print(e)
이제 열거형을 이용해 value 값과 위치 값을 가져오게 된다. 위에서 추출한 원본 사진이 위치한 링크로 이동한 다음 이미지를 저장한다. 그렇게 하고, 진행 경과를 출력해준다.
이렇게 작성한 코드를 합쳐서 실행하면 다음과 같은 실행 결과를 얻을 수 있다.
여기까지가 새로운 내용을 정리한 것이고 다음은 다음 날 진행할 프로젝트에 관한 주제를 선정하는 시간을 가졌다.
2. 프로젝트 주제 선정
이번 프로젝트는 데이터 크롤링 기술을 사용해야 한다는 조건이 있고, ESG와 관련된 내용을 다루는 것이 좋을 것 같다는 의견이 있었다. 우리 조는 지역별 안전재난 문자 데이터를 추출해와 산사태, 폭염, 한파 등의 자연 재해의 빈도를 계산하는 주제로 정했다. 하지만 ESG와 연관 짓기 위해 내일 더 자세한 내용을 다룰 것이다.
'ABC부트캠프 데이터 탐험가 과정' 카테고리의 다른 글
[17일차] ABC 부트캠프 취업 역량 강화 활동 (0) | 2024.07.28 |
---|---|
[16일차] ABC 부트캠프 데이터 분석 프로젝트 발표회 (0) | 2024.07.28 |
[14일차] ABC 부트캠프 동적 크롤링을 이용한 노래 가사 분석 (11) | 2024.07.24 |
[13일차] ABC 부트캠프 동적 크롤링 및 시각화 (1) | 2024.07.23 |
[12일차] ABC 부트캠프 ESG Day(데이터로 보는 분야) (2) | 2024.07.20 |