안녕하세요.
저번 시간에 파트너스 API를 통해서 상품정보를 가져오는 것까지 했습니다.
오늘은 쿠팡에 있는 상품 이미지 가져오는 방법에 대해서 설명하겠습니다.
API를 호출해 가져온 상품정보에 접속할 수 있는 URL이 있었는데요.
그 URL를 통해 상품페이지로 접속해서 이미지를 가져올꺼에요. 오늘꺼 조금 깁니다…

용어 대~충 설명

  • 파싱 : 가져오는 것? ㅋㅋ (ex. 문자열을 파싱한다 = 문자열을 가져온다)

이번에 설명할 내용

  • 상품URL을 타고 상품페이지에 접속해서 상품타이틀, 이미지 가져오기

시작하기 전에 간단히 알아야할 것들

  • 웹페이지는 구성하는 요소에는 정적인 정보와 동적인 정보가 있습니다. 정적인 정보는 일반적인 html 태그라고 생각하시면 되고 동적인 정보는 자바스크립트가 들어가있는 부분이라고 생각하시면 돼요.
  • 근데 이 자바스크립트는 웹브라우저에서 처리를 해주기 때문에 웹브라우저로 접속하지 않으면 처리가 안되서 정보를 가져올 수가 없습니다.
  • 그래서 웹브라우저를 컨트롤할 수 있는 놈을 이용하는데요. 보통 “셀레니움"을 사용합니다(저는 셀레니움밖에 몰라서 다른것도 있는지 모르겠네요 ㅎㅎ)
  • 셀레니움이 웹브라우저를 컨트롤 하는건 아니고, 브라우저별로 웹드라이버가 있는데 그 웹드라이버를 셀레니움을 이용해서 컨트롤할 수 가 있어요 ㅎㅎ

셀레니움 설명

  • 출처 : https://www.slideshare.net/JiLee24/selenium-113082253
  • 암튼 중요한 것은 웹드라이버가 필요하고 셀레니움으로 컨트롤 한다는 것입니다.
  • 다들 크롬을 많으 쓰시니까 크롬웹드라이버를 이용할 꺼고, 셀레니움은 파이썬 셀레니움 패키지를 설치하면 됩니다.

크롬웹드라이버 다운

파이썬 v3 셀레니움 패키지 설치

  • 파이썬은 패키지설치할때 pip를 사용합니다. 우리는 파이썬 v3 이니깐 pip3 이겠죠?ㅎㅎ
  • 명령어 창에서 “pip3 install selenium” 이렇게 치시면 설치됩니다. 저는 이미 설치되어 있으니까 already ~~ 하고 나오네요. 셀레니움 설치

코드의 흐름 및 간단 설명

    1. 웹드라이버 실행
    1. URL로 상품페이지 접근
    1. 타이틀, 이미지 찾기
    1. 이미지 다운로드

1. 웹드라이버 실행

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# ~~
	self.options = webdriver.ChromeOptions()
	self.options.add_argument('headless')
	self.options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36")
	self.options.add_argument("lang=ko_KR")
	self.webdriverpath = os.getcwd() + r"\chromedriver.exe"

# ~~

	driver = webdriver.Chrome(self.webdriverpath, options=self.options)
	time.sleep(5)
  • 웹드라이버를 소스코드랑 동일한 폴더에 위치해 놓으셔야 됩니다.
  • 웹드라이버를 실행할때 다양한 옵션들을 줄수가 있습니다. 제가 제공하는 코드에는 이런저런 옵션이 있는데요.
  • 음 그냥 크롤링(자동으로 돌아다니면서 웹페이지를 파싱하는 것) 방지를 우회하기 위해서 넣어놨다고 생각하시면 됩니다.
  • 필요없는 옵션들도 있는데 그냥 뭐가 필요하고 안필요한지 구분하는것도 귀찮아서 우선 넣어 놨습니다.
  • 선택가능한 옵션은 headless 입니다. 프로그램이 동작하는 걸 보고싶은 분은 삭제하시거나 주석처리해서 실행해보세요. 자동으로 웹브라우저가 떠서 동작하는 걸 보실 수 있을꺼에요.
  • 저 옵션을 설정하는게 컴퓨터의 리소스를 적게 먹으니가 보통 설정해 놓는 편이에요^^. 개발할때에는 빼놨다가 다 끝나면 설정하는 편입니다.
  • 중간에 sleep()이 있는데요. 실행하는데 시간이 조금 걸릴테니까 기다려주는 부분이라고 생각하시며 됩니다.

2. URL로 상품페이지 접근

1
2
	producturl = each_product['productUrl'] 
	driver.get(producturl)
  • 간~단합니다. 저번시간에 키워드로 검색하는 API 써서 정보를 얻었을때 보면 “productUrl” 이라는 요소가 있었습니다. 그 요소에 접근해서 url을 가져오고 웹드라이버를 컨트롤 해서 접근합니다.

3. 타이틀, 이미지 Element 찾기

  • 웹페이지에서 타이틀과 이미지 엘리먼트를 찾을꺼에요. 이 부분은 음 설명은 할텐데 이해가 안가실 수도 있어요.
  • 궁금하신분은 개인적으로 좀더 찾아보셔야 될 것 같습니다.
  • 웹페이지를 구성하는 엘리먼트들에는 이름들이 있어요. 그래서 그 이름을 이용해서 찾으면 됩니다.
  • 이름을 찾는 방법은 정보를 보고싶은 엘리먼트에다가 마우스를 올리신 후 “Ctrl + Shift + c"를 누르시면 개발자도구가 뜨면서 엘리먼트에 대한 정보를 볼 수 있을 꺼에요.
  • 쿠팡에서 “크리스마스 가랜드"로 검색해서 나오는 상품하나를 예로 들어 볼께요. 크리스마스 가랜드
  • 타이틀에다가 마우스 올리고 “Ctrl + Shift + c"를 누르면 이렇게 뜹니다.
  • 대충 설명드리면 h2 태그에 클래스 이름이 prod-buy-head__title 이네요. 이 이름을 가지고 접근하면 정보를 얻을 수 있어요.
  • 여러가지 이름들이 있는데 이름이 유일할때는 한방에 접근할 수 있고 유일하지 않을 때는 점진적으로 찾아가서 접근해야 됩니다.
1
	title = driver.find_element_by_class_name("prod-buy-header__title").text
  • 클래스명으로 엘리먼트를 찾아서 해당 요소의 텍스트 내용을 읽어오는 코드에요.
  • 이젠 이미지를 찾아볼께요. 이미지를 찾아서 이미지의 출처를 통해 이미지를 다운받을꺼에요.
  • 동일하게 그림에다가 마우스 올리고 단축키 누르면 개발자 도구가 뜨면서 요소의 정보가 보입니다. 이미지 찾기
  • 근데 이놈은 “subType-IMAGE” 라는 클래스의 하위에 있는데요. 저 클래스 하위의 이미지 요소를 찾으면 제대로 찾아지지가 않아요.
  • 왜냐하면 “subType-IMAGE” 라는 클래스는 저 페이지에서 너무 많거든요.
  • 그래서 이미지 엘리먼트 상위의 유일하게 접근할 수 있는 요소를 찾아서 접근해 나갈꺼에요. 그 애가 바로 “detail-item"입니다.
  • 클래스 이름이 “detail-item” 엘리먼트 하위의 이미지를 정보를 가져오는 거죠!
1
	img = driver.find_elements_by_xpath("//*[@class='detail-item']//img")
  • 클래스 이름이 “detail-item"인 엘리먼트 하위의 이미지를 가져오고있습니다. 그리고 이미지 엘리먼트가 여러개일 수 있기 때문에 함수이름에 s가 있는거 보이시죠^^? find_elements_by_xpath()

3. 이미지 다운받기

  • 이미지는 소스코드가 위치한 폴더에 imgs라는 폴더에 저장할꺼에요. 자동으로 만들어지게 되어있습니다.
  • 이미지를 다운받기 위해서는 출처를 알아야되는데, 출처는 이미지 엘리먼트의 “src” 라는 속성에서 가져올 수 있습니다.
  • 그리고 유효한 상품이미지가 가지고 있는 몇가지 패턴들이 있어요. 그런 패턴을 가지고 있지 않은 이미지들은 다운로드 하지 않도록 되어있습니다.
  • 저장될때의 이미지 명은 랜덤으로 생성되게 되어있어요. 사용자가 하나하나 정하기로 그렇고, 정해서 하면 이름이 겹칠 확률도 높기때문에 겹칠확률이 적도록 적당히 긴 랜덤이름으로 저장되게 되어있습니다.
1
2
3
4
5
6
7
	for each_img in img:
		src = each_img.get_attribute('src')
		if 'vendor_inventory' not in src and ('thumbnail' not in src or 'remote' not in src):
			continue
		fname = secrets.token_hex(16)[0:10] + ".png" 
		fnamefull = self.imgpath + "\\" + fname
		urllib.request.urlretrieve(src, fnamefull)
  • 하.. 설명이 다 끝났네요. 길다 길어. 너무 전문적이지 않게 적당히 설명한다고는 했는데 잘 전달됐을지 모르겠네요.

코드​

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# coding: utf-8
 
import hmac
import hashlib
import os
import time
import requests
import json
import urllib.request
from selenium import webdriver
import secrets
from urllib.parse import urlencode
from PIL import Image
from io import BytesIO

__author__ = "Jaejin Jang<jaejin_me@naver.com>"

class cupangMgr:
	def __init__(self):
		self.DOMAIN = "https://api-gateway.coupang.com"

		if not os.path.isdir('imgs'):
			os.makedirs('imgs')

		self.imgpath = os.getcwd() + r"\imgs"

		self.options = webdriver.ChromeOptions()
		self.options.add_argument('headless')
		self.options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36")
		self.options.add_argument("lang=ko_KR")
		self.webdriverpath = os.getcwd() + r"\chromedriver.exe"

	def generateHmac(self, method, url, secretKey, accessKey):
		path, *query = url.split("?")
		os.environ["TZ"] = "GMT+0"
		datetime = time.strftime('%y%m%d')+'T'+time.strftime('%H%M%S')+'Z'
		message = datetime + method + path + (query[0] if query else "")
		signature = hmac.new(bytes(secretKey, "utf-8"), message.encode("utf-8"), hashlib.sha256).hexdigest()

		return "CEA algorithm=HmacSHA256, access-key={}, signed-date={}, signature={}".format(accessKey, datetime, signature)

	def get_productsdata(self, request_method, authorization, keyword, limit):
		URL = "/v2/providers/affiliate_open_api/apis/openapi/products/search?keyword=" + urllib.parse.quote(keyword) + "&limit=" + str(limit)
		url = "{}{}".format(self.DOMAIN, URL)

		response = requests.request(method=request_method, url=url, headers={ "Authorization": authorization, "Content-Type": "application/json;charset=UTF-8" })
		retdata = json.dumps(response.json(), indent=4).encode('utf-8')
		jsondata = json.loads(retdata)
		data = jsondata['data']
		productdata = data['productData']

		return productdata

	def make_productcontent(self, each_product):
		driver = webdriver.Chrome(self.webdriverpath, options=self.options)
		time.sleep(5)

		producturl = each_product['productUrl'] 
		driver.get(producturl)
		driver.execute_script("Object.defineProperty(navigator, 'plugins', {get: function() {return[1, 2, 3, 4, 5]}})")
		driver.execute_script("Object.defineProperty(navigator, 'languages', {get: function() {return ['ko-KR', 'ko']}})")
		driver.execute_script("const getParameter = WebGLRenderingContext.getParameter;WebGLRenderingContext.prototype.getParameter = function(parameter) {if (parameter === 37445) {return 'NVIDIA Corporation'} if (parameter === 37446) {return 'NVIDIA GeForce GTX 980 Ti OpenGL Engine';}return getParameter(parameter);};")
		time.sleep(5)

		title = driver.find_element_by_class_name("prod-buy-header__title").text
		img = driver.find_elements_by_xpath("//*[@class='detail-item']//img")

		images = []

		for each_img in img:
			src = each_img.get_attribute('src')
			if 'vendor_inventory' not in src and ('thumbnail' not in src or 'remote' not in src):
				continue
			fname = secrets.token_hex(16)[0:10] + ".png" 
			fnamefull = self.imgpath + "\\" + fname
			urllib.request.urlretrieve(src, fnamefull)
			images.append(('image', (fname, open(fnamefull, 'rb'), 'image/png')))
		driver.close()

		return title, producturl, images

if __name__ == '__main__':
	method = 'GET'				 #정보를 얻는것이기 때문에 GET
	keyword = '채워 넣으세요' #검색할 키워드, 쿠팡에서 검색하는거랑 결과가 동일합니다.
	limit = 5					 #몇개의 정보를 가져올지 설정. 상위부터 가져옵니다.
	access_key = '채워 넣으세요.'			#API access key
	secret_key = '채워 넣으세요.'		#API secret key
	URL = "/v2/providers/affiliate_open_api/apis/openapi/products/search?keyword=" + urllib.parse.quote(keyword) + "&limit=" + str(limit)

	test = cupangMgr()
	authorization = test.generateHmac(method, URL, secret_key, access_key)		# HMAC 생성
	productdata = test.get_productsdata(method, authorization, keyword, limit)	# API 호출

	for each_product in productdata:
		title, producturl, images = test.make_productcontent(each_product)
		print('타이틀 : ', title)
		print('URL : ', producturl)
		print('이미지파일 : ', images)
  • 실행하시면 아래그림처럼 파싱해온 결과들이 출력되고, imgs폴더에 이미지가 다운로드 된것을 확인하실수 있습니다.

실행 및 결과

궁금한 점은 질문해주세요^^ 다음 포스팅에는…

  • 네이버 블로그 API로 상품정보 올리는 방법방법과
  • ☆☆☆개꿀팁!! 리뷰 평점 가져오는 방법☆☆☆ 올려드리겠습니다.