DP - 7번일지 (이미지 크롤링 by. Python, Selenium)

Debug-Life ·2023년 1월 2일
0

DP(가제) 어플 개발

목록 보기
7/11

오늘의 목표
파이썬을 이용해서 이미지 크롤링에 성공하기.
셀레니움이라는 라이브러리를 통해서 직접 인터넷으로 이미지를 찾는 과정을 코드로 가능하게끔 해준다. (ex. 크롬창을 열고, 검색어를 입력하고, 이미지를 마우스 우클릭으로 저장하는 과정들)
추가로 셀레니움이라는 라이브러리로 크롤링 뿐만 아니라 메일보내기 같이 인터넷으로 하는 모든 것들을 자동화 할 수 있음.


1. 파이썬 설치

(파이썬 공식문서)
경로 설정 부분 꼭 체크하고 설치
vscode로 폴더 생성해서 폴더 열어놓고 터미널 실행.


2. Selenium으로 가상 환경 설치

셀레니움 공식문서
python -m venv selenium 처럼 셀레니움 install 하기 전 앞에 python 커맨드를 입력해줘야 제대로 설치가 됨.
설치후에 해당 폴더 경로에 selenium 파일 생성됨을 확인.

  • activate 파일 실행하려 했지만 업데이트 때문인지 해당 명령어가 실행안됨.
    그래서 파일 경로 찾아가는 커맨드 .\activate 로 가상환경 실행성공
    (왼쪽 아래 selenium이라는 녹색 글씨로 가상환경 실행 여부 확인가능함.)

  • 구버전으로 동작할거라서 터미널에
    pip3 uninstall selenium
    pip3 install selenium==3.141 입력


3. 웹 브라우저 세팅

  • ex) 크롬으로 진행 크롬드라이버 링크

  • 현재 본인의 크롬 버전에 맞춰서 드라이버 설치 후 vscode에 selenium 폴더안에 복사 붙여넣기

  • 똑같이 셀레니움 폴더안에 google.py 파일 생성

  • 파이썬으로 셀레니움 예제 코드 복사 (공식문서)

    -그러면 이제 가상환경인 셀레니움을 인식못해서 사진처럼 에러가 날텐데

당황말고 vscode를 눌러서 찾기를 누른다음
selenium 폴더 > Scripts > python.exe 를 선택하면 셀레니움 가상환경 설정이 되어서 에러 사라짐.

4. 셀레니움 테스트

1. 5,6번라인 제외 후 아래는 주석처리, Firefox로 되어있던거를 Chrome으로 변경

2. google.py 폴더 위치로 가서 파이썬 실행 python google.py 커맨드 입력

3. 파이썬 공식홈페이지가 크롬창으로 열림 크롬이 자동화된 소프트웨어 의해 제어되고 있습니다라는 문구가 뜨면 성공

에러 발생

  • 그럼이제 구글 크롬에서 이미지를 크롤링 하기 위해 구글 주소를 대신 입력해보았지만... 여전히 쉽지 않다. 경로 설정 문제인데...

  • vscode에서 터미널이 아니라 출력 부분을 보았었음. 무슨 실수인지 모르겠는데 우측 상단에 파일 실행하는것과 터미널에서 python google.py이 다르게 동작 되었음. ( 아마 다른 파일경로로 들어가서 터미널에서 잘못입력했거나, 다른 파이썬 파일을 선택하고 실행 버튼을 클릭한 것 같음.)


아니다 다시 찾아보니, 경로 설정을 제대로 해줘야 한다. 3가지 방법이 있다.
실행하려는 webdriver.exe 파일의 위치는 상대경로가 아닌
절대경로로 해주는게 확실해서 좋다. 우리가 보통 쓰는 경로는 아래와 같다.
browser = webdriver.Chrome("C:\Users\chromedriver.exe")
하지만 프로그래밍 언어에서는 아래와 같이 바꿔 써줘야 한다.


1. r 을 써준다.
browser = webdriver.Chrome(r"C:\Users\chromedriver.exe")
가장 간단한 방법이다.


2. \를 한번 더 붙여줌으로써 escape처리를 한다.
browser = webdriver.Chrome("C:\\Users\\chromedriver.exe")
\뒤에 문자를 써 주면 그 문자 그대로 나타내주는 법칙을 이용 한 것 같다.
경로가 길어지면 힘들다.


3. \를 /로 교체한다.
browser = webdriver.Chrome("C:/Users/chromedriver.exe")
이것도 간단하지만 경로가 길어지면 힘들다. 가장 간단한 방법인 1번을 추천한다.


나는 1번으로 해결했다. (참고블로그)

5. 이미지 크롤링 시작

5-1. 셀레니움으로 구글 검색창에 원하는 글자 입력까지 실행

  1. 웹페이지에서 해당 요소 찾는법 : 12라인에 보면 q로 찾음. 검색창 부분의 name이 q임

  2. 웹페이지에서 원하는 입력값 보내는법 : 14라인을 보면 elem.send_keys("pycon") 로 pycon이라는 입력값을 보낼 수 있다. 나는 테니스공이라고 적어두고 파이썬 실행 하면 아래와 같은 창이 열리는걸 확인 할 수 있다.


  3. 엔터키 어떻게 입력하는데? 검색하면 된다. (해당 언어, 동작간단 명료하게. 안되면 전부 영어로 검색해보자.)
    elem.send_keys(Keys.RETURN)입력.
    (내가 주석처리한 코드에서 이미 나와있었다. )


  4. 성공

5-2. 이제 이미지 저장까지

  1. 위에서 했던것과 똑같이 클래스든 속성이든 이미지에 공통적인 부분을 개발자 도구를 열어서 찾아준다. 여기선 class이고 class="rg_i Q4LuWd" 부분. 확인


  2. elements , class로 찾기
    중요한게 위에서 검색창을 찾을땐 find_element 였지만 사진 저장에는 여러개를 동시에 저장할것이기 때문에 find_elements로 찾아주고 css의 class로 찾을 것이기 때문에 앞에 .을 붙여준다.


  3. 에러발생 IndexError: list index out of range 가 떴다.


  4. 띄어쓰기 문제. class가 두개라서 띄어쓰기 한거 고대로 갖다 붙여넣은게 문제였다. 30분 뻘짓 경험
    해결..!

  1. 구버전 에러
  • find_element_by_css_selector를 사용할때는 class를 하나만 넣어줘야 에러가 안난다.
  • 2023.01.03 기준 최신 버전의 pip에서는 find_element_by_css_selector대신 find_element만 사용한다.
  • 그런데 구글 큰 이미지의 class는 n3VNCb KAlRDb 로 두개다. 근데 구버전의 pip 로 진행했기 때문에 n3VNCb 하나만 넣어줘서 에러 해결.

라고 생각했지만 전혀 틀린 문제였다.
17번 라인처럼 새롭게 바뀐 문법으로 작성해야 한다.
구글에 Python selenium elements example 로 검색해서 들어가면 매우 친절하게 나와있다.

적용해서 실행해보면 (원래대로 class를 두개 넣던 상관없다.)


성공!
참고 블로그


6. 이미지를 다운로드 에러발생
  • 나무위키 등 특정 사이트의 경우 봇이 접근하는 것을 차단해서 조코딩님이 추가해주신 코드 추가함.
opener=urllib.request.build_opener()
opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
urllib.request.install_opener(opener)
urllib.request.urlretrieve(imgUrl, "test.jpg")

  • src로 주소를 찾았고 해당 이미지를 내 프로젝트 폴더에 다운하는것까지 성공함. test.jpg

5-3. 여러 이미지 저장

images에 작은 사진파일들 전부 담아주고
for문으로 돌면서 하나씩 저장해준다. 이름은 1~50으로 정해짐

images = driver.find_elements_by_css_selector(".rg_i.Q4LuWd")
count = 1
for img in images:
   img.click()
   time.sleep(3)
   # print(driver.find_element_by_css_selector(".n3VNCb").get_attribute("src"))
   imgUrl = driver.find_element(By.CSS_SELECTOR, ".n3VNCb").get_attribute("src")
   opener=urllib.request.build_opener()
   opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
   urllib.request.install_opener(opener)
   urllib.request.urlretrieve(imgUrl, str(count) + ".jpg")
   count = count + 1

5-4. 무한 스크롤

  • 이미지를 다운하는데 까지 성공했지만 50개까지 밖에 다운 안되는 문제가 생겼다. 그래서 무한 스크롤 찾아봄.
  • 아래 코드로 스크롤 제일 밑까지 내린 후 이미지 다운하도록 코드 위에 붙여넣기.

참고 사이트

SCROLL_PAUSE_TIME = 0.5

# Get scroll height
last_height = driver.execute_script("return document.body.scrollHeight")

while True:
    # Scroll down to bottom
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    # Wait to load page
    time.sleep(SCROLL_PAUSE_TIME)

    # Calculate new scroll height and compare with last scroll height
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height
  • 구글 검색창에서 스크롤 내리다가 나오는 결과 더보기 란 클릭해주려면
    break 부분에 driver.find_element(By.CSS_SELECTOR ,(".mye4qd")).click() 추가

  • 끝까지 내렸을때 더보기 란 없을떄 나는 에러 수정 코드

    if new_height == last_height:
        try:
            driver.find_element(By.CSS_SELECTOR ,(".mye4qd")).click() # 결과 더보기란#
        except:
            break
    last_height = new_height
  • 혹시 모를 에러 대비해서 try except 추가
for img in images:
    try: 
        img.click()
        time.sleep(0.5)
        # print(driver.find_element_by_css_selector(".n3VNCb").get_attribute("src"))
        imgUrl = driver.find_element(By.XPATH, "/html/body/div[2]/c-wiz/div[3]/div[2]/div[3]/div[2]/div/div[2]/div[2]/div[2]/c-wiz/div[2]/div[1]/div[1]/div[2]/div/a/img").get_attribute("src")
        opener=urllib.request.build_opener()
        opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
        urllib.request.install_opener(opener)
        urllib.request.urlretrieve(imgUrl, str(count) + ".jpg")
        count = count + 1
    except:
        pass

class 선택 부분

css selector로 하지말고 full xpath로 해줘야 더 정확함.
class 이름이 겹칠떄도 있기 떄문에.

profile
인생도 디버깅이 될까요? 그럼요 제가 하고 있는걸요

0개의 댓글