이미지 빌드, 로컬 테스트, 소스코드 수정 및 재빌드까지
이번 포스트에서는 Docker를 이용하여 Python 환경에 Chrome과 SeleniumBase를 포함하는 이미지를 구축하는 방법을 단계별로 설명합니다. 이 환경은 이후 Cloud Run과 Cloud Tasks를 활용해 대량 크롤링 작업을 분산 실행할 때도 유용하게 사용할 수 있습니다.
프로젝트 폴더 생성
먼저 로컬에 새 폴더(예: my-selenium-app)를 생성합니다.
VSCode를 실행하고 File > Open Folder...를 선택하여 이 폴더를 엽니다.
필수 파일 구성
프로젝트 폴더 내에 아래와 같은 파일들을 생성합니다:
my-selenium-app/
├── Dockerfile
├── requirements.txt (선택사항: 추가 Python 패키지 목록)
└── test_search.py (예제 테스트 소스 코드)
멀티스테이지 빌드를 사용하면 변경 가능성이 낮은 기본 환경(Python+Chrome)과, 자주 바뀌는 소스 코드(예: 크롤링 스크립트)를 분리할 수 있어 빌드 캐시를 효율적으로 사용할 수 있습니다.
VSCode에서 Dockerfile 파일을 열고 아래 내용을 입력하세요:
[dockerfile]
# Stage 1: Base - Python 3.11-slim과 Chrome을 설치 (변경 가능성이 낮은 기본 환경)
FROM python:3.11-slim as base
# 시스템 필수 패키지 설치 (wget, gnupg, ca-certificates)
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
gnupg \
gnupg1 \
gnupg2 \
ca-certificates && rm -rf /var/lib/apt/lists/*
# 구글 크롬 설치 (공식 키와 저장소 추가)
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list \
&& apt-get update && apt-get install -y --no-install-recommends google-chrome-stable && rm -rf /var/lib/apt/lists/*
# 크롬 실행에 필요한 라이브러리 설치
RUN apt-get update && apt-get install -y --no-install-recommends \
libnss3 \
libgconf-2-4 \
libappindicator3-1 \
fonts-liberation && rm -rf /var/lib/apt/lists/*
# Stage 2: Dependencies - pip 종속성 설치 (SeleniumBase 등)
FROM base as deps
WORKDIR /app
# (옵션) requirements.txt를 사용할 경우, 아래 두 줄 주석 해제
# COPY requirements.txt .
# RUN pip install --upgrade pip && pip install -r requirements.txt
# 여기서는 SeleniumBase를 직접 설치
RUN pip install --upgrade pip && pip install seleniumbase
# Stage 3: Application - 자주 변경되는 소스 코드 복사
FROM deps as final
WORKDIR /app
COPY . .
EXPOSE 8080
# CMD를 환경변수 PORT를 사용하여 Python 내장 HTTP 서버를 실행하도록 함
CMD ["sh", "-c", "python -m http.server ${PORT:-8080}"]
참고:
CMD는 테스트용으로 Python 내장 HTTP 서버를 실행합니다.
나중에 실제 크롤링 또는 웹 애플리케이션 실행 시, CMD를 해당 실행 명령어로 변경하면 됩니다.
프로젝트 폴더 내에 test_search.py 파일을 생성하고 아래 코드를 붙여넣습니다. 이 코드는 50개의 검색어를 10개씩 배치로 나눠 구글 검색을 실행하는 예제입니다.
import time
from seleniumbase import SB
from selenium.webdriver.common.keys import Keys
def search_keyword(keyword):
"""단일 검색어로 구글 검색 후 결과 페이지 제목을 반환"""
with SB(uc=True, test=True, locale="ko") as sb:
sb.open("https://www.google.com")
sb.wait_for_element("input[name='q']", timeout=10)
sb.type("input[name='q']", keyword)
sb.send_keys("input[name='q']", Keys.ENTER)
sb.wait_for_element("h3", timeout=10)
title = sb.find_element("title").text
return {"keyword": keyword, "title": title}
def run_batch(batch):
"""한 배치의 검색어들을 순차 실행"""
batch_results = []
for keyword in batch:
print(f"** 검색 실행: {keyword}")
result = search_keyword(keyword)
batch_results.append(result)
time.sleep(1) # 각 검색 사이 1초 딜레이
return batch_results
def main():
# 예시 50개의 검색어 목록 (원하는 검색어로 수정 가능)
keywords = [
"세탁기", "쿠쿠", "쿠쿠전자", "LG전자", "삼성", "다이슨", "엘지", "현대", "기타", "전자",
"컴퓨터", "휴대폰", "카메라", "음향기기", "스마트워치", "스피커", "프린터", "노트북", "태블릿", "TV",
"가전", "모니터", "마우스", "키보드", "스캐너", "드론", "로봇", "게임콘솔", "오디오", "빔프로젝터",
"냉장고", "세탁기2", "에어컨", "청소기", "전자렌지", "식기세척기", "커피머신", "전기밥솥", "헤어드라이기", "전기면도기",
"비데", "공기청정기", "로봇청소기", "스팀청소기", "와인셀러", "전자책", "블루투스", "스마트홈", "네스트", "AI가전"
]
# 10개씩 배치로 나누기
batch_size = 10
batches = [keywords[i:i+batch_size] for i in range(0, len(keywords), batch_size)]
all_results = []
for idx, batch in enumerate(batches, start=1):
print(f"\n=== 배치 {idx} 실행 중 ===")
batch_results = run_batch(batch)
all_results.extend(batch_results)
time.sleep(5) # 배치 간 5초 딜레이
print("\n전체 검색 결과:")
for res in all_results:
print(res)
if __name__ == "__main__":
main()
설명:
이 코드는 로컬에서 50개의 검색어를 10개씩 나눠서 실행합니다.
각 검색어별로 구글 검색 결과 페이지의 제목을 추출해 출력합니다.
프로젝트 폴더(my-selenium-app)에서 터미널(또는 VSCode 터미널)을 열고 아래 명령어를 실행합니다:
docker build --platform linux/amd64 -t my-seleniumbase-image .
이미지가 정상적으로 빌드되었는지 확인하려면 아래 명령어로 컨테이너를 실행합니다:
docker run --rm -e PORT=8080 -p 8080:8080 my-seleniumbase-image
이 명령은 컨테이너 내부에서 CMD로 설정한 python -m http.server ${PORT:-8080} 명령을 실행합니다.
브라우저에서 http://localhost:8080에 접속하여 Python HTTP 서버가 정상 실행되는지 확인할 수 있습니다.
테스트 코드 실행 확인:
만약 CMD를 "python", "test_search.py"로 변경했다면, 테스트 코드가 실행되어 각 검색어에 대한 로그와 결과가 터미널에 출력되어야 합니다.
소스 코드 수정:
VSCode에서 test_search.py 파일이나 다른 소스 코드를 수정합니다.
(이 단계는 자주 변경되는 부분이며, 기본 환경은 변경되지 않으므로 캐시가 활용되어 빌드 시간이 단축됩니다.)
이미지 재빌드:
수정 후 다시 아래 명령어로 이미지를 빌드합니다:
docker build --platform linux/amd64 -t my-seleniumbase-image .
컨테이너 재실행:
docker run --rm -e PORT=8080 -p 8080:8080 my-seleniumbase-image
변경된 소스 코드가 반영되어 테스트가 실행되는지 확인합니다.
Cloud Run 배포:
위 단계까지 로컬 테스트가 완료되면, 이미지를 Container Registry(GCR)에 Push하고 Cloud Run에 배포할 수 있습니다.
Cloud Tasks 분산 실행:
Cloud Tasks를 사용해 4500개 작업(예: 45개씩 100번)을 분산 실행하도록 Python 스크립트를 작성하여 Cloud Run 서비스의 엔드포인트를 호출할 수 있습니다.
추가)

실제로 로컬에서 나눠서 돌리면 이렇게 나온다!