실전 수익형 웹, 앱 서비스 동물상 테스트 만들기의
2번째 영상을 통해 제작된 코드입니다.
해당 내용에 도움이 되는 부분은 링크를 걸어두었습니다!
그럼 시작하도록 하겠습니다!
1편에서는 원하는 Beautiful Soup를 이용하여 원하는 키워드를 입력하면,
해당 키워드에 맞춰 이미지를 자동을 다운로드 받아지는 프로그래밍을 해봤다.
하지만 문제가 살짝 있다면, 보안상의 문제로 최근 브라우저 자체에서
사용자가 직접 Crawling
하는 것을 막아두었다고 한다.
그래서 그런지 사실 1편에서 이미지 다운로드 중 오류가 조금씩 있었지만
어찌저찌 다운로드가 가능은 했었다...
이러한 상황에서 희망으로 떠오른 것이 바로 Selenium
을 통한 Crawling
이다!
간단하게 이해한 바로는, Python
을 이용하여 프로그래밍을 위한
가상 작업 환경을 조성하고, Selenium
이라는 프레임워크를 통해
Crawling
작업을 할 수 있도록 하는 프로그래밍이라고 이해했다.
그럼 차근차근 작업을 시작할 차례!
우선 Python
의 가상 작업 환경을 조성해야 하는 이유를 설명하자면,
BeautifulSoup
, Request
등의 라이브러리에 따라 호환되는
Python
의 버전이 다르기 때문에 하나의 로컬 컴퓨터에서도 여러 개의
Python
의 버전이나 정보들을 분리하여 각 버전별로 환경을 가상으로 조성하고
이러한 가상 환경을 선택해서 사용하도록 하는 것이
Python
의 가상 환경 조성의 개념이다.
그렇다면 우선 Python
의 가상 환경을 조성해보자!
Python
의 가상 환경 생성을 위한 사이트, Python venv에서 방법을 찾아보도록 한다.
사이트를 보면 cmd
를 통한 가상 환경 명령어를 볼 수 있다.
python3 -m venv /path/to/new/virtual/environment
이렇게 나와있지만, 필자의 경우에는 python3
에서 3
을 지우고 실행했다.
물론 위의 코드에서 경로는 각자 다르게 해도 무관하다.
가상 환경을 생성했다면, cmd
를 통해
cd /path/to/new/virtual/environment/Scripts
위의 명령어를 통해 Python
가상 환경인 venv를 조성한 디렉토리의
Scripts로 이동한 후, cmd
를 통해
activate
위의 명령어를 입력하게 되면 가상 환경 생성이 완료된다!
그렇다면 가상 환경은 조성했고, Selenium
이라는 라이브러리를
다운로드 받아 가상 환경과 함께 사용하도록 해보자!
우선 Selenium
이 일반적인 방법과 달리 Crawling
을 수월하게
진행할 수 있는 원리에 대해 생각해 볼 필요가 있다.
일반적으로 BeautifulSoup
를 통한 Crawling
은 코드를 통해
html
의 정보를 Parsing
하는 원리라면,
Selenium
의 작동 원리는 실제 브라우저를 코드로 조작하는 원리로,
마우스의 움직임, 클릭, 스크롤과 같은 웹 동작들을 실행시켜
웹을 Crawling
해주는 원리이다.
결론적으로, 필자는 흔히 생각하는 메크로의 원리라고 이해했다.
그렇다면 마찬가지로 cmd
를 이용하여 설치를 해보자.
pip install selenium
위의 명령어를 통해 설치를 한 후, 먼저 조성한 가상 환경에 사용할
브라우저 실행 파일을 넣어줘야 한다. 왜냐!!!
생각해보면 굉장히 간단하다.
현재 사용하고 있는 로컬 컴퓨터의 웹은 가상 작업 환경이 아닌
실제 컴퓨터를 통한 로컬 작업 환경이고,
가상 환경의 경우 Python
과 Selenium
, 이 둘 밖에 설치된게 없다.
우리의 목적은 웹 Crawling
인데 중요한 웹이 없다.
그래서 웹 브라우저 실행파일을 따로 넣어주어야 한다.
필자의 경우 크롬 브라우저를 이용해 작업을 했다.
Downloads, 이 링크를 통해 크롬 브라우저 실행 파일을 다운받을 수 있다.
여기서 주의할 점이라고 하면, 로컬 환경의 크롬 버전과
chromedriver.exe
의 버전이 동일해야 한다.
현재 사용하는 크롬의 버전을 보는 방법은??
버전을 확인했다면, 버전에 맞게 링크를 들어가서
window
, mac
등의 각 운영 체제에 맞게 다운받으면 된다.
그렇게 다운받은 압축 파일을 압축 해제한 후에 chromedriver.exe
을
앞서 조성한 가상 환경 디렉토리에 이동시켜 준다.
그리고 chromedriver.exe
가 있는 디렉토리에 google.py
를 생성해준다.
여기서도 문제는 모든 환경은 조성이 되었을지 몰라도 코드에 대한 지식이
부족(없다싶이)하기 때문에 이 또한 구글링을 통해 어떻게 사용하는지에 대한
예제를 찾아보고 그러한 예제를 조금 더 응용하여 사용하도록 해보자...
python selenium example
라는 키워드는 검색하면
Simple Usage 이러한 사이트가 나온다.
Simple Usage
부분을 보면
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
driver.get("http://www.python.org")
assert "Python" in driver.title
elem = driver.find_element(By.NAME, "q")
elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()
위와 같은 코드를 볼 수 있다.
그렇다면 이 코드를 앞서 생성했던 google.py
에 에디터 툴을 통해 입력해보도록 하자!
미리 얘기를 하자면
Terminal
을 통한 작업이 굉장히 많은 관계로,
이러한 작업을 하는데 있어서 귀찮아질 것을 염려해서Atom
에서Visual Studio Code
로
에디터 툴을 바꿔서 사용하게 되었다.
그리고 실행을 해보면?
Python
공식 홈페이지가 열리는 것을 볼 수 있다.
여기서 주목할 것은 바로
이 부분이다!
가상 환경에서 Selenium
의 자동화 코드로 제어된다고 뜬다.
이렇게 코드의 실행은 해봤고, 이제는 응용을 할 차례!
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
위의 코드는 selenium
모듈에서 webdriver
를 불러오고,
selenium.webdriver.common.keys
모듈에서는 Keys
를,
selenium.webdriver.common.by
모듈에서는 By
를 불러온다는 뜻이고,
driver = webdriver.Firefox()
driver.get("http://www.python.org")
위의 코드는 웹 드라이버를 Firefox
로 실행한다는 코드를 driver
변수에 담고
이를 통해 Python
사이트를 불러온다는 뜻이다.
그렇다면 여기서 조성 환경에 따라 코드를 고쳐야 할 필요가 있다.
driver = webdriver.Google()
driver.get("https://www.google.co.kr/imghp?hl=ko&tab=ri&ogbl")
위의 코드처럼 드라이버는 Google
로, url
은 구글 이미지 검색 url
로 변경해줬다.
assert "Python" in driver.title
위의 부분은 코드가 실행되었을 때, title
에 해당하는 값이
Python
이라는 단어를 포함하고 있는지를 확인하는
일종의 보장의 개념이라고 필자는 이해했다.
이렇게 포함한다는 것을 가정하거나 하는 식으로 보장하는 프로그래밍을
'방어적 프로그래밍'이라고 불린다고 한다.
하지만 필자는 사용하지 않도록 하겠다.
저러한 보장 코드를 사용하는 것을 권장한다고는 하지만, 이해할 것은 태산이고...
이해를 위한Crawling
을 하는 것이기 때문에 해당 코드를 지우고 사용했다.
다음으로 더 해석해보자면,
elem = driver.find_element(By.NAME, "q")
위의 코드는 q
라는 name
태그를 가진 요소를 찾도록 하는 코드를 elem
변수에 담는다!
elem.clear()
다음 코드는 리스트에 있는 값을 삭제하는 코드인데
q
라는 name
태그를 가진 요소는 구글 검색창이기에 비워준다는 의미인 것 같다.
필자는 애초에 비워진 검색창에 검색어를 입력하기에 해당 코드를 삭제했다.
elem.send_keys("pycon")
위의 코드는 pycon
이라는 키워드를 검색창에 입력해주는 역할을 한다.
여기서 필자는 테스트를 위해 adidas
를 입력할 예정이다.
elem.send_keys(Keys.RETURN)
위의 코드는 키보드 입력 코드로, RETURN
은 엔터를 의미,
위의 코드로 실행 가능한 작업은 지정한 검색어 입력, 엔터 입력으로
원하는 키워드의 이미지를 검색하는 코드가 된다.
나머지 코드를 해석해보자면,
assert "No results found." not in driver.page_source
driver.close()
위의 코드에서 assert
문은 사용하지 않을 예정으로 넘어가고,
마지막 줄은 작업이 끝나면 웹 브라우저를 나가주는 코드이다.
이렇게 준비된 코드를 입맛에 맞게 수정해준 결과,
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.google.co.kr/imghp?hl=ko&ogbl")
elem = driver.find_element(By.NAME, "q")
elem.send_keys("adidas")
elem.send_keys(Keys.RETURN)
# driver.close()
# 브라우저 종료는 잠시 주석으로 처리
위의 코드를 에디터의 Terminal
로 실행하게 되면???
자동으로 검색창에 키워드 입력 후, 엔터까지 된다!!!
이제 원하는 것은 키워드에 맞는 이미지를 다운로드 받는 것!
위의 사진을 보면 작은 이미지 하나를 클릭하고,
오른편에 큰 사진이 나오게 되고 우리는 저 큰 고화질의 이미지를 다운받을 코드를 짜야한다.
그렇다면 먼저 해야할 것은??
작은 이미지를 클릭하는 코드와 작은 이미지의 class
, name
등의 태그 이름이다.
그렇다면 구글링!
python selenium click
이라는 키워드를 통해 검색한 결과,
python selenium click on button, 이 사이트에서 내려가다 보면 보이는 코드인,
driver.find_element_by_css_selector('.button .c_button .s_button').click()
이러한 코드를 볼 수 있다.
위의 코드는 사실 2가지의 팁을 알 수 있다.
하나는 .click()
, 또 하나는 .find_element_by_css_selector
우선 찾을 이미지의 class
, name
등의 태그 끝에 .click()
를 통해
클릭을 할 수 있다는 것을 알 수 있고,
.find_element_by_css_selector
를 통해 웹 페이지에 있는 모든 이미지의
class
, name
등의 태그를 알아내는 코드 이렇게 두 개인 셈이다.
우리가 찾을 작은 이미지는 여러개이기 때문에
.find_elements_by_css_selector
이렇게 elements
로 입력할 예정이다.
또한 찾으려는 작은 이미지의 태그 명을 보기 위해 크롬의 개발자 모드로~
위의 이미지처럼 빨간 표시인 '요소 선택'을 클릭하고,
작은 이미지를 클릭해서 작은 이미지의 정보를 확인한다.
확인하다 보면 빨간 부분처럼 class
명을 확인할 수 있다.
이렇게 알아낸 class
명과 .onclick
을 우리의 코드에 적용해 볼 차례!
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.google.co.kr/imghp?hl=ko&ogbl")
elem = driver.find_element(By.NAME, "q")
elem.send_keys("adidas")
elem.send_keys(Keys.RETURN)
driver.find_elements_by_css_selector('.rg_i.Q4LuWd')[0].click()
# 실제 class명은 rg_i Q4LuWd이지만 by_css_selector를 사용해서
# class명의 공백을 .으로 입력하여 rg_i.Q4LuWd이 됨
# [0]은 수많은 class 중에서 index값이 0인(맨처음) 이미지를 클릭한다는 의미
# driver.close()
# 브라우저 종료는 잠시 주석으로 처리
이제 작은 이미지를 클릭했다면, 앞서 봤던 큰 이미지가 켜지고 다운을 받아야 한다.
방금 알아봤던 개발자 모드를 이용해 큰 이미지의 class
명을 알아내보자!
하지만 class
만을 통해서는 다운을 받을 수 없으며,
저 큰 이미지의 url을 알아내야 한다.
또다시 찾아온 구글링 시간!
python selenium img src
라는 키워드를 통해 검색하고,
How to get img src in string in selenium using python라는 사이트에서 밑으로 내려 찾다보면,
src = driver.find_element_by_xpath("//div[@class='rc]/h3[@class='r']/a/img").get_attribute("src")
이러한 코드가 나온다.
위의 코드를 보면 id
나 class
가 아니라 xpath
라는 것의 src
를 알아내는 코드다.
이걸 가져온 이유는 작은 이미지와 다르게 큰 이미지의 경우,
id
나 class
의 이름이 다른 것들이 사이에 스파이처럼 껴있다.
그렇게 되면 오류가 생겨 코드가 종료되기 때문에
위의 이미지처럼 각각의 이미지의 id
나 class
의 이름이 다르더라도
최대한의 교집합으로써 xpath
를 사용해 안정적으로 원하는 이미지의
scr
를 얻어낼 수 있게 된다.
더욱더 안정적으로 scr
를 얻어내기 위해서
각각의 이미지의 full xpath
를 얻어서 코드에 적용시키도록 했다.
full xpath
를 구하는 방법은 다음과 같다.
위의 이미지처럼 해당 이미지의 코드에 우클릭을 한 후 복사를 클릭,
전체 xpath
복사를 클릭해서 코드에 적용시키면 된다.
이렇게 코딩 작업을 한 결과,
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.google.co.kr/imghp?hl=ko&ogbl")
elem = driver.find_element(By.NAME, "q")
elem.send_keys("adidas")
elem.send_keys(Keys.RETURN)
driver.find_elements_by_css_selector('.rg_i.Q4LuWd')[0].click()
# 실제 class명은 rg_i Q4LuWd이지만 by_css_selector를 사용해서
# class명의 공백을 .으로 입력하여 rg_i.Q4LuWd이 됨
# [0]은 수많은 class 중에서 index값이 0인(맨처음) 이미지를 클릭한다는 의미
driver.find_element_by_xpath("/html/body/div[2]/c-wiz/div[3]/div[2]/div[3]/div/div/div[3]/div[2]/c-wiz/div/div[1]/div[1]/div[3]/div/a/img").get_attribute("src")
# driver.close()
# 브라우저 종료는 잠시 주석으로 처리
위의 코드가 완성된다.
이제 출력을 통해 src
를 알아내기 위해
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.google.co.kr/imghp?hl=ko&ogbl")
elem = driver.find_element(By.NAME, "q")
elem.send_keys("adidas")
elem.send_keys(Keys.RETURN)
driver.find_element_by_css_selector('.rg_i.Q4LuWd')[0].click()
# 실제 class명은 rg_i Q4LuWd이지만 by_css_selector를 사용해서
# class명의 공백을 .으로 입력하여 rg_i.Q4LuWd이 됨
# [0]은 수많은 class 중에서 index값이 0인(맨처음) 이미지를 클릭한다는 의미
print(driver.find_element_by_xpath("/html/body/div[2]/c-wiz/div[3]/div[2]/div[3]/div/div/div[3]/div[2]/c-wiz/div/div[1]/div[1]/div[3]/div/a/img").get_attribute("src"))
# driver.close()
# 브라우저 종료는 잠시 주석으로 처리
이렇게 print()
로 에디터의 Terminal
로 출력하면???
Bluetooth: bluetooth_adapter_winrt.cc:1074 Getting Default Adapter failed
이러한 Terminal
에서의 에러 문구가 나온다...
이유는 작은 이미지까지는 잘 클릭이 되었으나, 큰 이미지의 url
을 불러오는 과정에서
큰 이미지의 불러오기 위한 로딩 시간을 주지 않고
url
을 불러오면서 생기는 오류이다.
이러한 오류는 시간 지연을 주는 코드를 삽입하면서 해결이 가능하다.
import time
time.sleep(2)
위의 코드처럼 time
모듈을 불러와주고
2초 정도 지연시킴으로써 오류를 해결하면 된다.
이렇게 수정한 코드는
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
driver = webdriver.Chrome()
driver.get("https://www.google.co.kr/imghp?hl=ko&ogbl")
elem = driver.find_element(By.NAME, "q")
elem.send_keys("adidas")
elem.send_keys(Keys.RETURN)
driver.find_element_by_css_selector('.rg_i.Q4LuWd')[0].click()
# 실제 class명은 rg_i Q4LuWd이지만 by_css_selector를 사용해서
# class명의 공백을 .으로 입력하여 rg_i.Q4LuWd이 됨
# [0]은 수많은 class 중에서 index값이 0인(맨처음) 이미지를 클릭한다는 의미
time.sleep(2)
print(driver.find_element_by_xpath("/html/body/div[2]/c-wiz/div[3]/div[2]/div[3]/div/div/div[3]/div[2]/c-wiz/div/div[1]/div[1]/div[3]/div/a/img").get_attribute("src"))
# driver.close()
# 브라우저 종료는 잠시 주석으로 처리
위의 코드를 Terminal
을 통해 실행하면??
위의 이미지처럼 빨간 부분에 큰 이미지의 url
을 출력해준다.
하지만 우리가 원하는 것은 출력이 아닌 다운로드!
이것도 물론 구글링이다.
python download image by url
라는 키워드를 통해 들어간 사이트인
Downloading a picture via urllib and python에 들어가서 천천히 내리다보면 나오는
# Python 3
import urllib.request
urllib.request.urlretrieve("http://www.gunnerkrigg.com//comics/00000001.jpg", "00000001.jpg")
위의 코드를 활용해 보자!
간단하게 해석하자면, urllib.request
라는 url
요청 모듈을 불러오고
urllib.request.urlretrieve
를 사용하여 ("url", "다운로드명.jpg")
이렇게 지정해주면
다운로드가 된다고 한다!
이제 코드를 적용시키면
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
import urllib.request
driver = webdriver.Chrome()
driver.get("https://www.google.co.kr/imghp?hl=ko&ogbl")
elem = driver.find_element(By.NAME, "q")
elem.send_keys("adidas")
elem.send_keys(Keys.RETURN)
driver.find_element_by_css_selector('.rg_i.Q4LuWd')[0].click()
# 실제 class명은 rg_i Q4LuWd이지만 by_css_selector를 사용해서
# class명의 공백을 .으로 입력하여 rg_i.Q4LuWd이 됨
# [0]은 수많은 class 중에서 index값이 0인(맨처음) 이미지를 클릭한다는 의미
time.sleep(2)
imgUrl = driver.find_element_by_xpath("/html/body/div[2]/c-wiz/div[3]/div[2]/div[3]/div/div/div[3]/div[2]/c-wiz/div/div[1]/div[1]/div[3]/div/a/img").get_attribute("src")
# imgUrl이라는 변수에 담기
urllib.request.urlretrieve(imgUrl, "test.jpg")
# imgUrl 변수를 인자로 입력
# test.jpg는 임의로 정한 이미지 명
# driver.close()
# 브라우저 종료는 잠시 주석으로 처리
그리고 위의 코드를 Terminal
을 통해 실행하면???
urllib.error.HTTPError: HTTP Error 403: Forbidden
Terminal
에서 이러한 에러를 뿜어낸다...
또다시 구글링의 방으로...
드디어...찾았다...
download image from url using python urllib but receiving HTTP Error 403: Forbidden의 결과
import urllib.request
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)
이해한 만큼으로 설명해보자면, 우리는 사람으로써 브라우저를 Crawling
하고 있기에,
브라우저 측에서 보안 이슈로 다운로드를 막아둔 듯하다.
그래서 우리는 headers
를 통해 브라우저가 코드를 실행 중이다 ~ 하고
크롬을 속여줘야 한다는 것이다.
그럼 다시 코드를 적용해보면
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
import urllib.request
driver = webdriver.Chrome()
driver.get("https://www.google.co.kr/imghp?hl=ko&ogbl")
elem = driver.find_element(By.NAME, "q")
elem.send_keys("adidas")
elem.send_keys(Keys.RETURN)
driver.find_element_by_css_selector('.rg_i.Q4LuWd')[0].click()
# 실제 class명은 rg_i Q4LuWd이지만 by_css_selector를 사용해서
# class명의 공백을 .으로 입력하여 rg_i.Q4LuWd이 됨
# [0]은 수많은 class 중에서 index값이 0인(맨처음) 이미지를 클릭한다는 의미
time.sleep(2)
imgUrl = driver.find_element_by_xpath("/html/body/div[2]/c-wiz/div[3]/div[2]/div[3]/div/div/div[3]/div[2]/c-wiz/div/div[1]/div[1]/div[3]/div/a/img").get_attribute("src")
# imgUrl이라는 변수에 담기
opener=urllib.request.build_opener()
opener.addheaders=[('Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.115 Safari/537.36')]
# 여기서 Chrome의 버전을 현재 버전의 것으로 수정
urllib.request.install_opener(opener)
urllib.request.urlretrieve(imgUrl, "test.jpg")
# imgUrl 변수를 인자로 입력
# test.jpg는 임의로 정한 이미지 명
# driver.close()
# 브라우저 종료는 잠시 주석으로 처리
그리고 Terminal
을 통해 실행시켜보자!
오늘은 이렇게 Python
의 가상 작업 환경을 조성하고 Selenium
을 통해
원하는 키워드에 맞는 이미지를 다운받는 작업을 해보았다.
지극히 개인적으로 1편의 웹
Crawing
은 오늘의 작업에 비하면 정말 아무것도
아닌 수준인 것처럼 오늘 코딩 작업이 어려웠다.
하지만 이런 코드들도 다뤄보면서 실력을 점점 키워가면 언젠가는...
컨텐츠 만들기에 성공하지 않을까 싶다.
다음 3편으로 계속 진행해보겠습니다~!