이미지 크롤러 - Naver
- 공식적인 방법으로 어플리케이션을 등록을 통해 API를 사용할 수 있다.
import urllib.request
import json
client_id = "XXXXXX"
client_secret = "XXXXXX"
encText = urllib.parse.quote("아이유")
url = "https://openapi.naver.com/v1/search/image?query=" + encText + "&sort=sim&display=100"
request = urllib.request.Request(url)
request.add_header("X-Naver-Client-Id", client_id)
request.add_header("X-Naver-Client-Secret", client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if (rescode == 200):
response_body = response.read()
response_json = json.loads(response_body.decode('utf-8'))
else:
print("Error Code:" + rescode)
- 웹드라이버를 이용한 방법에 비해 옛날 이미지가 많이 포함되어 있다.
- 매우 빠른 검색 속도
- 하루 25,000 쿼리 제한
- 쿼리당 최대 1000개의 이미지 획득가능
Selenium을 이용한 웹페이지 파싱
- Selenium 은 브라우저의 웹드라이버를 이용하여 웹사이트의 동작을 테스트한다. 따라서 현재 사용중인 브라우저 버전과 호환가능한 웹드라이버를 다운로드 받아야한다. 크롬 브라우저의 웹 드라이버는 link에서 다운로드할 수 있다.
- Naver 검색창의 웹페이지 동작을 분석하고 아래의 웹드라이버의 동작을 구현하여 이미지 url을 가져올 수 있다.
1. 키워드 검색
2. 스크롤
3. img 태그에서 src 속성값 획득
4. url 중복 제거
[Naver] 스크롤
- 네이버 이미지 검색에서 더 이상 스크롤 할수 없는 경우 로딩창의 style 속성에 display가 'none'으로 설정된다.
<div class="photo_loading _spinner ._listSpinner" style="display: none;">
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
def infinite_scroll_down(driver, wait=.5):
body = driver.find_element_by_tag_name('body')
while True:
body.send_keys(Keys.END)
if driver.find_elements(By.XPATH, '//div[contains(@class,"photo_loading")]')[0].get_attribute('style') == '':
time.sleep(wait)
else:
break
[Naver] 썸네일 이미지 가져오기
- 2021.1.26 기준으로 네이버 이미지 검색에서는 스크롤 위치에 따라 썸네일이 로드되며 이전에는 src 속성에 empty 값(
data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
)이 할당된다. 따라서 스크롤을 강제로 움직여 썸네일 이미지를 로드한 후 이미지의 url을 크롤링해야한다.
- (수정) 이미지의 src가 empty인 경우 data-lazy-src 속성에 썸네일 url이 있기 때문에 굳이 강제로 스크롤 하지 않아도 된다. 하지만
get_attrubute()
를 호출하는 시점에 따라 element의 상태가 다를 수 있기 때문에 반복검사를 수행하도록 구현하였다.
def get_thumbnail_urls(driver, wait=.1, retry=3):
empty_src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
urls = []
imgs = driver.find_elements(By.XPATH, '//img[@class="_image _listImage"]')
for img in imgs:
count = retry
while count:
src = img.get_attribute('src')
if src == empty_src:
src = img.get_attribute('data-lazy-src')
if src is not None and src != empty_src:
urls += [src]
break
count -= 1
time.sleep(wait)
print(f'{len(urls)}/{len(imgs)} images are loaded')
return urls
[Naver] 원본 이미지 가져오기
- 2021.1.26 기준으로 네이버 이미지 검색은 질의어에 대한 검색 결과들의 썸네일을 리스트업하고 썸네일 클릭시 우측에 원본 이미지와 유사 이미지를 제공한다.
- 원본과 썸네일 이미지는 사실 동일한 리소스임을 확인할 수 있다. 원본의 경우
https://search.pstatic.net/common/?src=xxxx%yyyy.jpg&type=sc960_832
와 같은 형식의 url을 얻을 수 있으며 썸네일은 https://search.pstatic.net/common/?src=xxxx%yyyy.jpg&&type=a340
와 같은 형식으로 썸네일 이미지가 따로 저장되어 있는 것이 아니라 호스팅 서버에서 동일한 이미지를 요청데이터에 따라 이미지 프로세싱하고 있음을 알 수 있다. 따라서 이전과 같은 방법으로 썸네일 주소를 획득하여 문자열 치환을 통해 원본을 얻을 수 있지만 직접 클릭을 통해 원본의 url을 얻는 방법으로 구현하였다.
- 원본이미지가 완전히 로드되기 전까지는 썸네일 url을 제공한다.
def get_image_urls(driver, wait=.1, retry=3):
def check_loaded(img):
return False if img.get_attribute('src').endswith('type=a340') else True
body = driver.find_element_by_tag_name('body')
body.send_keys(Keys.HOME)
imgs = driver.find_elements(By.XPATH, '//img[@class="_image _listImage"]')
urls = []
for n, img in enumerate(imgs):
if n == 0:
img.click()
count = retry
origin_img=driver.find_element(By.XPATH, '//div[@class="image _imageBox"]//img')
while count and not check_loaded(origin_img):
time.sleep(wait)
count -= 1
if check_loaded(origin_img):
urls.append(origin_img.get_attribute('src'))
body.send_keys(Keys.RIGHT)
print(f'{len(urls)}/{len(imgs)} images are loaded')
return urls
[Naver] ToDo
- 썸네일 & 원본 모두 질의어에 대한 결과만 가져오고 있으며 최대 500개의 이미지를 얻을 수 있다. 클릭시 나타나는 우측의 유사 이미지 검색결과를 이용하여 더 많은 관련 이미지를 얻을 수 있다.
- URL 주소를 이용한 중복 제거의 개선 방법