최근 Google DV360 플랫폼에서 데이터를 크롤링하기 위해 Cloud Run Job을 병렬로 실행하는 구조를 도입했다. 하지만 병렬 실행 시 예상하지 못한 문제들이 발생하기 시작했다. 대표적인 이슈들은 다음과 같다.
이 글은 해당 문제를 분석하고 해결 방안을 적용해나가는 과정, 그리고 궁극적으로 어떤 구조로 안정화를 이뤘는지에 대한 기록이다.
Google의 2단계 인증은 TOTP(Time-based One-Time Password) 기반이다. 즉, 같은 키(secret
)를 사용하는 경우 30초 간 동일한 OTP 값이 생성된다. 따라서 동시 실행된 여러 개의 크롤링 Job은 모두 동일한 OTP를 사용하게 된다.
문제는 이 OTP가 "1회성"이라는 점이다. 한 번 제출되면 같은 값으로 다시 인증할 수 없다.
결과적으로:
하나의 Job이 성공적으로 로그인하고 세션 파일(dv360_session.json
)을 GCS에 저장했더라도,
restore_session()
시도 → 실패 → OTP 진입 시도restore_session()
시 로그인 성공 여부 판단을 위해 "identifierId"
HTML 요소 존재 여부만 판단했는데, 이는 불완전하다. 보안 페이지나 에러 페이지에서도 존재할 수 있어 로그인 성공 여부 판단이 정확하지 않다.
지금까지의 상황을 요약하자면 다음과 같다.
OTP는 30초 간격 TOTP -> 동일한 OTP가 동시 제출되면 하나만 성공
세션 덮어쓰기 문제 -> 여러 Job이 동시에 세션 저장/읽기 시도 시 꼬임 발생
불완전한 로그인 판별 -> HTML 요소만으로는 로그인 성공 여부 판단 불가
기존에는 OTP 인증 Job과 크롤링 Job을 분리하려고 했으나, 모든 Job이 세션을 우선 시도하고 실패하면 로그인으로 전환하는 방식이 더 유연하다고 판단했다.
즉, Job이 다음 순서를 따르게 된다:
이 구조는 단일 OTP Job을 따로 운영하지 않아도 되며, 실제 실패 상황에만 인증을 수행하여 충돌을 방지할 수 있다.
try:
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//div[text()='캠페인']"))
)
return True
except TimeoutException:
return False
web = DV360Crawler()
web.open_chrome_programmatically()
sleep(3)
if not web.restore_session(plan_name):
logging.info("세션 복원 실패 → OTP 로그인")
web.login(plan_name)
else:
logging.info("세션 복원 성공 → 로그인 생략")
def login(self, plan_name):
if self.b.html_includes("identifierId"):
self.b.find_one("#identifierId").send_keys(DV360_LOGIN_ID)
self.b.find_one("#identifierNext").click()
sleep(2)
self.b.find_one("input[name='password']").send_keys(DV360_LOGIN_PW)
self.b.find_one("#passwordNext").click()
sleep(5)
otp_success = False
try:
otp_success = self.get_code(plan_name)
except Exception as e:
logging.error(f"OTP 인증 실패: {e}")
if otp_success:
cookies = self.b.driver.get_cookies()
with open("/tmp/dv360_session.json", "w") as f:
json.dump(cookies, f)
self.upload_session_file("/tmp/dv360_session.json", "session/dv360_session.json")
해당 구조로 변환하면서, 다음과 같은 기준을 충족할 수 있었다.
이 구조는 OTP 기반 인증 시스템의 병렬 처리에서 안정적이며 확장성을 가지고 있기 때문에 유사한 크롤링 환경에서도 충분히 재사용가능할 것 같다.