Color hunt 사이트 API 두 개 만들기
color hunt 사이트의 api를 만들기 전, 해당 홈페이지의 color set들의 정보를 crawling을 이용해서 가져와야한다.
한 페이지에 모든 내용이 있는 경우 Beautifulsoup만 사용해서 정보를 가져올 수 있으나 color hunt페이지는 스크롤을 내려서 아래쪽의 정보도 가져와야하기 때문에 selenium을 이용해야한다.
지정한 시간동안 프로세스를 기다려 주는 역할 (무조건 지연)
만약 time.sleep(5)를 하면 코드 실행을 정확히 5초간 멈춘다.
보통 페이지 이동 후 에 쓰인다.
브라우저에서 사용되는 엔진 자체에서 파싱되는 시간을 기다려주는 메소드 (셀레늄에서만 사용하는 특수한 메소드) 보통 webdriver 첫 로딩시에 쓰인다.
implicitly_wait(10)은 요소가 존재할 때까지 최대 10초 동안 대기한다.
즉, 10초 전에 브라우저에서 파싱이 완료되면 10초를 기다리지 않고 바로 다음 코드로 넘어간다. 반대로 10초를 기다렸는데 파싱이 끝나지 않았으면 에러가 발생하고 바로 종료된다.
위의 내용은 이 곳의 답변을 정리하여 작성하였다.
Synchronously Executes JavaScript in the current window/frame
import time
import csv
from selenium import webdriver
from bs4 import BeautifulSoup
file = open("color_hunt.csv", mode="w")
wr = csv.writer(file)
wr.writerow(["c4","c3","c2","c1"])
# 1
driver = webdriver.Chrome('/Users/jinachoi/jina/chromedriver')
driver.implicitly_wait(3)
driver.get('https://colorhunt.co/')
# 2
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(3)
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
# 3
html = driver.page_source
soup = BeautifulSoup(html,'html.parser')
# 4
palette=soup.find_all('div',{'class':'palette'})
for color in palette:
c4 = color.find('div',{'class':'place c4'}).find('span').string
c3 = color.find('div',{'class':'place c3'}).find('span').string
c2 = color.find('div',{'class':'place c2'}).find('span').string
c1 = color.find('div',{'class':'place c1'}).find('span').string
wr.writerow((c4,c3,c2,c1))
driver = webdriver.Chrome('/Users/jinachoi/jina/chromedriver')
위의 명령어를 이용하여 driver라는 webdriver객체를 만들어주었다. Chrome뒤에 있는 경로는 내 컴퓨터에 chromedriver가 존재하는 장소의 위치이다.
driver.implicitly_wait(3)를 이용하여 웹사이트가 로드될 때 까지 기다린다.
driver.get('https://colorhunt.co/')을 이용하여 사이트를 열었다.
driver.execute_script("return document.body.scrollHeight")를 이용하여 스크롤을 동작시킬 수 있다.
2-1. last_height = driver.execute_script("return document.body.scrollHeight")
스크롤 높이를 last_height로 저장한다.
2-2. driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
Scroll을 아래로 내린다.
2-3. time.sleep(3)
로드될 때까지 3초 기다리기
2-4. new_height = driver.execute_script("return document.body.scrollHeight")
스크롤이 된 후의 높이를 계산하고 new_height로 지정한다.
2-5. 그 이후
이후 last_height와 new_height를 비교하고 높이가 같으면 (더 이상 내려가지 않은 것 이므로) 스크롤 종료하기
스크롤 내리기는 여기를 참고했다.
html = driver.page_source 을 이용하여 스크롤을 내리고 렌더링한 페이지를 가져온다.
이 문서에 bs4를 이용하여 크롤링을 진행할 것이다.
bs4를 이용하여서 원하는 내용을 찾아서 csv에 저장하도록 하였다.
# color/models.py
from django.db import models
class Color(models.Model):
c4 = models.CharField(max_length=50)
c3 = models.CharField(max_length=50)
c2 = models.CharField(max_length=50)
c1 = models.CharField(max_length=50)
class Meta:
db_table = "colors"
이후 makemigrations, migrate를 해주었다.
upload.py를 만들어서 위에서 크롤링하여 csv로 저장한 내용을 database에 옮겨주었다.
# upload.py
import csv
import os
import django
import sys
os.chdir(".")
print("Current dir=", end=""), print(os.getcwd())
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print("BASE_DIR=", end=""), print(BASE_DIR)
sys.path.append(BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "color_hunt.settings")
django.setup()
from color.models import Color
# color
CSV_PATH = './color_hunt.csv'
with open(CSV_PATH, newline='') as csvfile:
data_reader = csv.DictReader(csvfile)
for row in data_reader:
Color.objects.create(
c4 = row['c4'],
c3 = row['c3'],
c2 = row['c2'],
c1 = row['c1']
)
# color/views.py
import json
from django.views import View
from django.http import HttpResponse, JsonResponse
from .models import Color
class ColorSetView(View):
def get(self,request):
colors = Color.objects.select_related('id','c4','c3','c2','c1').values()
color_list =[
{"id":color.get('id'),
"set":[color.get('c4'),color.get('c3'),color.get('c2'),color.get('c1')]
}for color in colors]
return JsonResponse({"data":color_list}, status=200)
class DetailView(View):
def get(self,request,id):
colors=Color.objects.select_related('c4','c3','c2','c1').filter(id=id).values()
color_set = [
{"id": id,
"set": [color.get('c4'),color.get('c3'),color.get('c2'),color.get('c1')]
}for color in colors]
return JsonResponse({"data":color_set},status=200)
아래의 내용은 app에 추가된 urls이다.
# color/urls.py
from django.urls import path
from .views import ColorSetView,DetailView
urlpatterns = [
path('/colors',ColorSetView.as_view()),
path('/<int:id>',DetailView.as_view())
]
아래의 내용은 project에 추가된 urls이다.
# color_hunt/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('color', include('color.urls')),
]
위의 내용을 토대로 api를 만들고 확인하였다.
확인한 api는 여기서 확인할 수 있다.