본문 바로가기
프로젝트 일지/BMT

0. 크롤링 코드를 짜기 위한 길고 험난한 여정과 깨달음

by 데브겸 2023. 2. 28.

서울시에서 제공하는 실시간 도착 정보에 모든 열차에 대한 실시간 도착 정보가 있지는 않다. 따라서 실시간 도착 시간 정보 대신, api에서 데이터 베이스 정보가 갱신된 시간과 열차의 원래 도착 예정 시간 등을 계산하여 도착 정보를 구하고자 한다.

 

그 전에 서울시 지하철 실시간 도착 api는 특정 호선에 대한 정보를 제공해주지 않기 때문에, 네이버에서 제공되는 지하철 도착 시간표를 크롤링하는 것으로 하였다. 이번 주에는 이 지하철 도착 시간표를 크롤링할 수 있는 크롤러를 만드는 것을 목표로 하였다. 그 과정에서 챌린징한 것들이 많아 기록해두려 한다.

 

 

챌린지 1: (비교적) 크롤링하기 쉬운 정보 출처 찾기

 

 모바일 버전으로 사이트에 접속하여 '{}호선 {}역'으로 검색을 하면 아래 화면과 같이 지하철 전체 시간표를 제공해주는 화면이 나온다. 신기한 것은 pc 버전의 웹사이트는 전혀 다른 UI/UX가 적용되어 있다. 

 

왼쪽이 모바일 버전, 오른쪽이 pc 버전이다

이 다음에 나올 이미지에서도 볼 수 있겠지만, 모바일 버전의 화면이 훨씬 더 정보를 취득하기 쉬운 구조로 되어 있다. 오른쪽 웹사이트에서 정보를 취득하기 위해선 크롤링 후 정말 복잡한 데이터 처리가 필요하지만, 왼쪽 모바일에서는 상대적으로 매우 쉬운 구조로 데이터가 정렬되어 있다.

 

 

'전체 시간표' 부분을 클릭하면 아주 깔끔하고 직관적이게 정보가 정리되어 있는 것을 볼 수 있다. 웹페이지를 크롤링할 때 하나의 서비스 안에서도 PC버전 / 모바일 버전의 화면이 각각 다를 수 있다는 것을 기억해야 할 것 같다. 특히, 모바일의 경우 웹에 비해 훨씬 더 직관적이고 쉬운 UX를 적용해야 하므로, 더 깔끔하고 쉽게 크롤링할 수 있을 것 같다는 생각이 들었다. (다른 사람에게 물어보니 크롤링할 때는 모바일 버전에서 하는 경우가 더 쉽고 좋다고 하더라)

 

 

챌린지 2: 동적 웹사이트에서 크롤러 선택

 

우선 가장 익숙한 툴인 beautifulsoup으로 크롤링을 시도하다가 처참히 실패하게 되는데...

나는 빨간 박스를 친 부분 중 'contents_wrap' 클래스 아래에 있는 내용들을 크롤링 해와야 하는데 아무리 해봐도 'c10jv2ep' 태그까지만 출력이 나오고, 그 하위에 있는 태그들이 전혀 없는 것이었다... 이에 대해서 한참 고민하게 되는데...

 

 

 

알고보니 내가 가져오려는 부분이 사용자의 클릭을 받아야만 데이터를 불러오는 파트였기 때문이었다. 즉, 사용자가 '전체 시간표' 부분을 클릭해야만 'contents_wrap' 부분의 데이터가 나타나는 것이다. 최초로 저 검색 페이지에 접속하면 클릭이 되지 않은 상태이기 때문에 당연히 c10jv2p' 이하로 유의미한 정보가 따로 없었던 것이다.

 

따라서, beautifulsoup만으로 크롤링을 하는 것은 불가능해졌다. 웹페이지의 조작이 필요하기 때문에 selenium을 섞어서 코드를 짜는 것으로 전략을 수정하였다.

 

내가 작업해야 하는 것의 성격을 명확히 하고, 그에 맞는 도구를 선택하는 과정의 중요성을 느꼈다. 처음에 selenium을 활용하여 코드를 짜려고 했지만, selenium의 속도가 상대적으로 느리고, 리소스가 무겁다는 단점을 보고(관련 링크)는 아무 생각없이 requests, urllib이나 beautifulsoup을 사용하려고 했었던 것 같다. (scrapy의 경우 마감 시간이 얼마 남지 않았고, 아예 새로 익혀야 하기 때문에 선택지에서 배제했었다) 하지만, 천천히 생각해보니 전체 시간표를 크롤링하는데는 그렇게까지 속도가 중요하지 않을 수도 있을 것 같다. 실시간 도착 정보 (00분 00초 남았음) 등이 아니라, 전체 시간표를 가져오는 것이기 때문에 하루에 한 번 혹은 1시간에 한 번 배치성으로 데이터를 가져와도 괜찮을 것 같다. 더불어 모든 호선에 대해서 진행하는 것이 아니라 서울시 실시간 지하철 도착 api에서 지원하지 않는 호선에 대한 데이터만 필요하기 때문에 처리해야 할 호선의 수, 역의 갯수도 드라마틱하게 많지 않을 것이다.

 

 

챌린지 3: Selenium webdriver와의 싸움... 😇

 

이제 도구도 선택을 했으니 본격적으로 코딩을 시작하려 했다. 하지만 나에게 시련이 또 닥쳤으니... 바로 webdriver 설정에서 계속 오류가 뜨는 것이었다. 정확히는 'WebDriverException: Message: unknown error: cannot find Chrome binary'라는 에러였다.

 

이것저것 찾아보니, options를 통해서 chrome app 파일의 위치를 파라미터 값으로 넣어주는 방법도 있고 (링크)

(나는 맥을 쓰고 있어서) homebrew를 통해서 chrome app과 chrome binary를 reinstall하는 방법도 있었다 (링크)

하지만 죽어도 colab에서 안 돌아가는 것이다... 계속해서 같은 오류를 뱉어내고 있었다. 아니,,, Applications/chrome\ app에 아주 분명히, 내가 gui 상으로도 보이는 파일을 못 찾는 것에 아주 극대노하였다.

 

그러다가 정말 우연히 어떤 블로그 글을 보게 되고 (링크) 그 분은 바로 로컬에서 돌리시길래 colab이 아니라 로컬로 돌렸더니 글쎄 한 방에 해결되는 것이다... 로컬에서 한 방에 되는 것을 보고 좀 허망했지만... 그래도 된다는 것에 위안을 얻고 작업을 하기 시작했다.