* 브라우저를 띄우지 않고 메모리에만 selenium을 띄워 크롤링하기

  1. 기존 코드( https://blog.himion.com/176 )와 거의 유사하다.
  2. headlessDriver() 함수가 추가되었다
'''
* 구글 이미지 가져오기 ver. Headless
'''

import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import undetected_chromedriver as uc

import urllib
import time, datetime

ITEM_LIST = [ "Keith Thompson", "Zdzislaw Beksinski", "dariusz zawadzki"] # 1번
FOLDER = 'google' # 2번
IMG_XPATH = '//*[@id="Sva75c"]/div[2]/div/div[2]/div[2]/div[2]/c-wiz/div/div/div/div[3]/div[1]/a/img[1]' # 3번
SIGNINURL = 'https://accounts.google.com/signin/v2/identifier?hl=ko&passive=true&continue=https%3A%2F%2Fwww.google.com%2F&ec=GAZAmgQ&flowName=GlifWebSignIn&flowEntry=ServiceLogin'
ID = 'xxxx@gmail.com' # 4번
PASSWORD = 'xxxx' # 5번

def main():
  start = check_start() # 시간 측정 시작
  driver = headlessDriver()# headless를 적용하고 싶을때
  driver.get(SIGNINURL)
  googleSignIn(driver)# 구글로그인하고
  
  for searchItem in ITEM_LIST:
    saveDir = makeFolder(searchItem)
    
    url = makeUrl(searchItem)# 검색할 url 가져와서
    driver.get(url)# 이미지 검색으로 가서
    maximizeWindow(driver)# 창최대화
    scrollToEnd(driver)

    forbiddenCount = saveImgs(driver, saveDir, start)# 모든 상세 이미지 src들을 가져온다
    sec = check_time(start)
    print(f'실패수{str(forbiddenCount)}, {sec}, {datetime.datetime.now().time()}')
  time.sleep(10)
  driver.quit() 
  
def headlessDriver():
  options = uc.ChromeOptions()
  options.headless=True
  options.add_argument('--headless=new')
  driver = uc.Chrome(options=options)
  return driver

# 구글 로그인
def googleSignIn(driver):
  idBtn = driver.find_element(By.XPATH,'//*[@id="identifierId"]')# id 입력칸
  idBtn.send_keys(ID)
  nextBtn = driver.find_element(By.XPATH,'//*[@id="identifierNext"]/div/button')
  nextBtn.click()# 다음 버튼 클릭

  # 아래 코드는 비밀번호 요소가 화면에 나타날때가지 10초간 기다리는 코드이나
  # 비번의 경우 not interactive elem라서 에러가 뜬다. 하지만 돌아가는 코드이니 기다림이 필요할때 쓰자.
  try:
    passwordBtn = WebDriverWait(driver, timeout=10).until(EC.presence_of_element_located( (By.XPATH,'//*[@id="password"]/div[1]/div/div[1]/input') ))
    time.sleep(4)
    passwordBtn = driver.find_element(By.XPATH,'//*[@id="password"]/div[1]/div/div[1]/input')# 비밀번호 입력칸
    passwordBtn.send_keys(PASSWORD)
    passwordNextBtn = driver.find_element(By.XPATH,'//*[@id="passwordNext"]/div/button')
    passwordNextBtn.click()# 비밀번호 다음 버튼
    print('구글 로그인 성공')
    # driver.implicitly_wait(10)
  except OSError as e:
    print(e)
    
  time.sleep(20)# 휴대폰 본인 인증등의 시간이 충분히 필요하다


# 구글 이미지 검색 url 만들기
def makeUrl(searchItem):
  url = 'https://www.google.com/search'
  params ={# q와 tbm이 필수
    'q'     : searchItem,
    'tbm'   : 'isch',
  }
  url = url + '?' + urllib.parse.urlencode(params)
  return url


# 폴더 생성
def makeFolder(searchItem):
  saveDir = os.path.join(os.getcwd(), 'data', f'{FOLDER}_{searchItem}')
  try:
    if not(os.path.isdir(saveDir)): # 해당 폴더가 없다면
      os.makedirs(os.path.join(saveDir)) # 만들어라
    return saveDir
  except OSError as e:
    print(e+'폴더 생성 실패')

# 창 최대화
def maximizeWindow(driver):
  driver.maximize_window()

# 모든 이미지 목록을 가져오기 위해 무한 스크롤 다운
def scrollToEnd(driver):
  prev_height = driver.execute_script('return document.body.scrollHeight')
  print(f'prev_height: {prev_height}')
  
  while True:
    time.sleep(1) #네이버는 sleep없이 이동할 경우 무한로딩에 걸린다.
    driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
    time.sleep(3)
    
    cur_height = driver.execute_script('return document.body.scrollHeight')
    print(f'cur_height: {cur_height}')
    if cur_height == prev_height:
      print('높이가 같아짐')
      break
    prev_height = cur_height
  # 페이지를 모두 로딩한 후에는 최상단으로 다시 올라가기
  driver.execute_script('window.scrollTo(0, 0)')

# 모든 이미지들을 저장한다
def saveImgs(driver, saveDir, start):
  time.sleep(1)
  forbiddenCount = 0
  imgs = driver.find_elements(By.CSS_SELECTOR, '.rg_i.Q4LuWd')
  img_count = len(imgs)
  print(f'전체 이미지수 : {img_count}')
  # 하나씩 클릭해가며 저장
  for imgNum, img in enumerate(imgs): # imgNum에 이미지번호가 0부터 들어간다
    try:
      img.click()
      time.sleep(3)
      
      # 아래의 xPath는 자주 바뀌는 것 같다. 나머지는 고정인거 같으니 이것만 가끔 확인해주자
      bigImg = driver.find_element(By.XPATH, IMG_XPATH)
      src = bigImg.get_attribute('src')
      urllib.request.urlretrieve(src, saveDir + '/' + str(imgNum) + '.jpg')
      sec = check_time(start)
      print(f'{imgNum+1}/{img_count} saved {sec}')

    except Exception as e:
      print(e)
      forbiddenCount += 1# 저장 실패한 개수. forbidden이나 파일에러도 꽤 많다
      continue
  return forbiddenCount


# 시간 측정
def check_start():
    start_time = time.time()
    print("Start! now.." + str(start_time))
    return start_time
def check_time(start):
    end = time.time()
    during = end - start
    sec = str(datetime.timedelta(seconds=during)).split('.')[0]
    return sec
main()

+ Recent posts