ABOUT ME

IT와 컴퓨터 관련 팁, 파이썬 등과 아파트 정보, 일상적인 경험 등의 생활 정보를 정리해서 올리는 개인 블로그

  • 구글 이미지 검색 후 크롤링
    코딩 연습/파이썬 크롤링 2022. 5. 20. 21:20
    반응형

    '용산 차막힘' 관련 이미지를 검색하다가 구글 이미지 검색 후 다운로드하는 파이썬 크롤링 코드를 만들어 보기로 했다. 2021.10월에 이미지 구글링 관련 포스팅 글(구글에서 원하는 이미지 다운로드)에 이은 두번째 크롤링 코드다.  

     

     

    [파이썬 크롤링] 구글 이미지 다운로드

    이전 포스팅과 차이점은

    • 크롬 브라우저의 버전 부분에 맞는 selenium 크롬 웹 드라이버를 자동으로 설치되도록 모듈을 적용하였고,
    • selenium 업그레이드로 html 요소 추출하는 코드를 버전에 맞게 적용하였다.
    • 추출할 이미지 숫자를 지정하면 그 숫자까지만 추출한다. 

     

    1. 페이지 스크롤링 안 한 상태에서 이미지 추출하는 파이썬 코드

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.chrome.options import Options
    from webdriver_manager.chrome import ChromeDriverManager
    from selenium.webdriver.common.by import By
    import os, time, random
    from bs4 import BeautifulSoup
    import urllib.request
    
    
    def chromeWebdriver():
        options = Options()
        options.add_argument("lang=ko_KR")  # 언어 설정
        # options.add_argument("start-maximized") # 창 크기 최대로
        options.add_argument("disable-infobars")
        options.add_argument("--disable-extensions")    
        options.add_experimental_option('detach', True)  # 브라우저 안 닫히게
        options.add_experimental_option('excludeSwitches', ['enable-logging'])  # 시스템 장치 에러 숨기기
        user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36'
        options.add_argument(f'user-agent={user_agent}')    
        # options.add_argument('--headless')  # 웹 브라우저를 시각적으로 띄우지 않는 headless chrome 옵션
        driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options) 
        return driver
    
    
    def collect_image(search_word):
        url = 'https://www.google.co.kr'
    
        now = time.localtime()
        today_time = f'{now.tm_year}{now.tm_mon}{now.tm_mday}_{now.tm_hour}{now.tm_min}{now.tm_sec}'
        print(today_time)
    
        file_path = "c:\\temp\\"
    
        os.chdir(file_path)
        os.makedirs(file_path + today_time + '_' + search_word)
        os.chdir(file_path + today_time + '_' + search_word)
        file_save_dir = file_path + today_time + '_' + search_word
        print(file_save_dir)
    
        driver = chromeWebdriver()
        driver.get(url)
        time.sleep(random.uniform(2, 3))
        elem_q = driver.find_element(By.NAME, 'q')
        elem_q.send_keys(search_word)
        elem_q.submit()
    
        driver.find_element(By.LINK_TEXT, '이미지').click()  # 텍스트 메뉴 '이미지' 링크 클릭
        # driver.find_element(By.XPATH, '//*[@id="hdtb-msb"]/div[1]/div/div[2]/a').click()
        time.sleep(random.uniform(1, 2))
    
        file_no = 1
        count = 1
        img_src = []
    
        html = driver.page_source
        soup = BeautifulSoup(html, 'html.parser')
        imgs = driver.find_elements(By.CSS_SELECTOR, '#islrg > div.islrc > div a.wXeWr.islib.nfEiy')
        print(len(imgs))
    
        for img in imgs:
            img_src1 = img.click()  # 이미지 클릭 시 display 되는 url을 찾기 위해 클릭함
            img_src2 = driver.find_element(By.CSS_SELECTOR, '#Sva75c > div > div > div.pxAole > div.tvh9oe.BIB1wf > c-wiz > div > div.OUZ5W > div.zjoqD > div.qdnLaf.isv-id > div > a')
            time.sleep(random.uniform(0.2, 0.5))
            img_src3 = img_src2.find_element(By.TAG_NAME, 'img').get_attribute('src')
            if img_src3[:4] != 'http':
                continue
            print(count, img_src3, '\n')
            img_src.append(img_src3)
            count += 1
    
        for i in range(len(img_src)):
            extention = img_src[i].split('.')[-1]
            ext = ''
            print(extention)
            if extention in ('jpg', 'JPG', 'jpeg', 'JPEG', 'png', 'PNG', 'gif', 'GIF'):
                ext = '.' + extention
            else:
                ext = '.jpg'        
            try:
                urllib.request.urlretrieve(img_src[i], str(file_no).zfill(3) + ext)
                print(img_src[i])
            except Exception:
                continue
            file_no += 1
            # time.sleep(random.uniform(0.1, 0.5))
            print(f'{file_no}번째 이미지 저장-----')
    
        driver.close()
    
    
    if __name__ == '__main__':
        collect_image('고양이')
    • C:\ 드라이브 Temp 폴더에 이미지 저장 폴더를 생성한다.
    • time.localtime() 모듈의 반환값 time.struct_time(tm_year=2022, tm_mon=5, tm_mday=20, tm_hour=9, tm_min=37, tm_sec=51, tm_wday=4, tm_yday=140, tm_isdst=0)을 이용해서 폴더 이름을 만드는데 사용한다.
    • 구글에서 "고양이"로 검색한 후 selenium 크롬 웹 드라이버로 검색된 이미지 전체 요소를 추출한다.
    • 구글 이미지는 클릭 시 우측에 원본 이미지가 다시 표시되는데, 이때 클릭된 이미지 요소를 개발자 도구(F12)에서 확인해보면 원본 이미지의 html 코드 하단에 display 된다.
    • 이미지 링크가 있는 <img> 태그를 직접 지정하면 어떤 원인인지 몰라도 에러가 발생하여 바로 위 <a> 태그를 기반으로 <img>에 접근하여 속성 src를 가져왔다. (이때, 인터벌이 필요하여 time 적용 후 실행함)
    • 구글의 이미지 특성상 추출 결과가 data:image/jpeg;base64,/9j/4AAQS ~ 로 된 src는 작은 이미지일 가능성이 있어서 리스트 슬라이싱으로 비교하여 http로 시작되는 url만 추출함.
    • 이미지 확장자는 'jpg', 'JPG', 'jpeg', 'JPEG', 'png', 'PNG', 'gif', 'GIF'인 경우는 그대로 붙이고 나머지는 'jpg'로 붙임
    • 추출된 이미지 URL 리스트를 대상으로 urllib.request.urlretrieve()를 활용하여 이미지를 저장한다.
    • 크롬 브라우저를 띄우지 않고 작업하려면 주석 처리된 # options.add_argument('--headless')의 주석을 푼다.

     

     

    good4me.co.kr

     

    [실행 결과]

    터미널 출력
    터미널 출력

     

    생성된 폴더에 이미지 저장
    생성된 폴더에 이미지 저장

     

    2. 페이지 스크롤링 후 이미지 추출하는 파이썬 코드

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.chrome.options import Options
    from webdriver_manager.chrome import ChromeDriverManager
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    import os, time, random
    from bs4 import BeautifulSoup
    import urllib.request
    
    
    def chromeWebdriver():
        options = Options()
        options.add_argument("lang=ko_KR")  # 언어 설정
        # options.add_argument("start-maximized") # 창 크기 최대로
        options.add_argument("disable-infobars")
        options.add_argument("--disable-extensions")    
        options.add_experimental_option('detach', True)  # 브라우저 안 닫히게
        options.add_experimental_option('excludeSwitches', ['enable-logging'])  # 시스템 장치 에러 숨기기
        user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36'
        options.add_argument(f'user-agent={user_agent}')    
        # options.add_argument('--headless')  # 웹 브라우저를 시각적으로 띄우지 않는 headless chrome 옵션
        driver = webdriver.Chrome(service=Service(executable_path=ChromeDriverManager().install()), options=options)
        return driver
    
    
    def collect_image(search_word, extract_img_count):
        url = 'https://www.google.co.kr'
    
        now = time.localtime()
        today_time = f'{now.tm_year}{now.tm_mon}{now.tm_mday}_{now.tm_hour}{now.tm_min}'
        print(today_time)
    
        file_path = "c:\\temp\\"
    
        os.chdir(file_path)
        os.makedirs(file_path + today_time + '_' + search_word)
        os.chdir(file_path + today_time + '_' + search_word)
        file_save_dir = file_path + today_time + '_' + search_word
        print(file_save_dir)
    
        driver = chromeWebdriver()
        driver.get(url)
        time.sleep(random.uniform(2, 3))
        elem_q = driver.find_element(By.NAME, 'q')
        elem_q.send_keys(search_word)
        elem_q.submit()
    
        driver.find_element(By.LINK_TEXT, '이미지').click()  # 텍스트 메뉴 '이미지' 링크 클릭
        # driver.find_element(By.XPATH, '//*[@id="hdtb-msb"]/div[1]/div/div[2]/a').click()
        time.sleep(random.uniform(1, 2))
    
        # 페이지 스크롤 다운
        def page_scrolling(drivers):
            ## scrolling ------------------------------
            elem = driver.find_element(By.TAG_NAME, 'body')
            page_height = driver.execute_script('return document.body.scrollHeight')
            # print(page_height)
    
            # more_view_cnt = 0
            scroll_cnt = 1
            more_view_scroll_cnt = -1  # '결과 더보기' 버튼 나올 때의 scroll_cnt (break 처리 위해 사용)
            equal_cnt = 1
            while True:
                elem.send_keys(Keys.PAGE_DOWN)
                time.sleep(random.uniform(0.3, 0.5))
                new_height = driver.execute_script('return document.body.scrollHeight')
                if page_height != new_height:
                    page_height = new_height
                    equal_cnt = 1
                print(f'scroll_cnt: {scroll_cnt}, new_height: {new_height}, equal_cnt: {equal_cnt}')
                
                try:
                    scroll_cnt += 1
                    equal_cnt += 1
                    driver.find_element(By.XPATH, '//*[@id="islmp"]/div/div/div/div[1]/div[2]/div[2]/input').click()  # 결과 더보기 버튼 처리
                    print('결과 더보기 버튼 클릭 처리')
                    more_view_scroll_cnt = scroll_cnt
                    more_view_cnt += 1
                except:
                    if equal_cnt == 20:  # scroll_cnt / more_view_scroll_cnt > 2.5:
                        break
                    continue
            ## End of scrolling ------------------------------
    
        page_scrolling(driver)
    
        file_no = 1
        count = 1
        img_src = []
    
        html = driver.page_source
        soup = BeautifulSoup(html, 'html.parser')
        # print(soup)
        # imgs = driver.find_elements(By.TAG_NAME, 'img')
        imgs = driver.find_elements(By.CSS_SELECTOR, '#islrg > div.islrc > div a.wXeWr.islib.nfEiy')
        print(len(imgs))
    
        for img in imgs:
            img_src1 = img.click()  # 이미지 클릭 시 display 되는 url을 찾기 위해 클릭함
            try:
                img_src2 = driver.find_element(By.CSS_SELECTOR, '#Sva75c > div > div > div.pxAole > div.tvh9oe.BIB1wf > c-wiz > div > div.OUZ5W > div.zjoqD > div.qdnLaf.isv-id > div > a')
            except Exception:
                continue
            time.sleep(random.uniform(0.2, 0.5))
            img_src3 = img_src2.find_element(By.TAG_NAME, 'img').get_attribute('src')
            if img_src3[:4] != 'http':
                continue
            print(count, img_src3, '\n')
    
            img_src.append(img_src3)
            if count == extract_img_count + 10:  # 이미지 에러 대비해서 입력 숫자보다 크게 잡음
                break        
            count += 1
            
        print(f'\n{"="*10} 추출한 전체 리스트 {"="*10}\n{img_src}\n\n{"="*10}{len(img_src)}개 추출함{"="*10}\n')
    
        for i in range(len(img_src)):
            extention = img_src[i].split('.')[-1]
            ext = ''
            if extention in ('jpg', 'JPG', 'jpeg', 'JPEG', 'png', 'PNG', 'gif', 'GIF'):
                ext = '.' + extention
            else:
                ext = '.jpg'        
            try:
                urllib.request.urlretrieve(img_src[i], str(file_no).zfill(3) + ext)
                print(img_src[i])
            except Exception:
                continue
    
            print(f'{file_no}번째 이미지 저장-----')
            file_no += 1
            
            if file_no - 1 == extract_img_count:
                break
    
        driver.close()
    
    
    if __name__ == '__main__':
        collect_image('고양이', 200)
    • 구글 이미지 검색은 스크롤링을 하면 더 많은 이미지를 볼 수 있는데, 어느정도의 스크롤링 후 '결과 더보기' 버튼이 나온다. 이 버튼을 클릭한 후 다시 스크롤링을 하는데, '결과 더보기' 버튼이 2번은 안 나오는 것 같다.
    • 구글 검색 결과가 나오는 페이지의 상단 메뉴 중 '이미지' 링크 순서(전체 | 이미지 | 동영상 ~ 순서가 전체 | 동영상 | 이미지 등의 순서)가 바뀌면 안되기 때문에 LINE_TEXT로 하였으며, 이를 해결하는 방법은 구글 이미지 검색 URL을 이용하면 해결된다.
    반응형
Designed by goodthings4me.