글을 들어가기 전에, 크롤러에 대한 법적 문제가 굉장히 애매하다...

크롤러를 통해 일어난 법적인 이슈도 있다. 참고

링크의 사건은 2차 저작물에 대한 내용으로 볼 수 있겠지만..


크롤링이란게 기계적인 자동화를 시키는것이다 보니,

해당 서버에 크게 부하를 줄 수도 있어, 관리자의 입장에서는 공격으로 볼 수도 있다.

(이 요청을 매우 빠르게 반복 한다면 그게바로 Dos 공격이 되어버린다.)


첫 포스팅 이후 7월의 robots.txt 내용이다. 

본문에서 사용하는 페이지를 크롤링은 아직까지 금지하지 않았다...

(seo 과정에서 검색엔진의 인덱싱을 위해선 봇의 접근이 필요한데 왠만하면 금지하지 않을거라 예상한다.)


( 만약 문제가 있다면, 연락 부탁 드립니다. )



자 그럼 본론으로 들어가보자.


업무 도중 크롤러를 만들 일이 생겨 만들었는데, 이게 꽤나 매력적이다.

여러가지를 검토 해봤으나 나에겐 역시 파이썬이 제격인듯 하다.


각설은 그만하고 크롤러에 대해서 알아보자.


우선 크롤러란 무엇인가 ?

위키 : https://ko.wikipedia.org/wiki/%EC%9B%B9_%ED%81%AC%EB%A1%A4%EB%9F%AC


간단하게 웹을 탐색하는 과정을 자동화 시킨 프로그램이다.

그럼 크롤러를 통해 페이지를 가져오고, 해당 데이터들을 어떻게 담아 두느냐에 따라 제공할 수 있는 서비스가 달라질 수 있다.

검색 엔진의 경우 페이지의 url, 내용, 제목 등을 가져와 저장해두고, 저장된 데이터를 통해 검색 기능을 제공해주면 된다.


그럼 우리는 간단하게 CGV의 현재 상영중인 영화 정보를 전부 가져오는 크롤러를 만들어 보자.


먼저 페이지의 구조가 간단한 모바일 페이지를 분석하여 얻어보자.


아래의 링크는 강남CGV 의 2017년 3월 27일의 상영 정보이다.

http://m.cgv.co.kr/Schedule/?tc=0056&t=T&ymd=20170327&src=

쿼리 스트링을 보면 딱 추측이 된다. 

  - tc : 지점 코드

  - ymd : 날짜

  - src : 뭔지 못찾았지만 없어도 알아서 리다이렉트 된다.


Get 방식으로 스케쥴러에서 리스팅을 한다는걸 알 수 있다.


하지만 HTML소스를 확인해보면, 

해당 날짜의 컨텐츠를 가져오지 않고 있는걸 확인할 수 있다.


이유는 Ajax 로 리스트를 가져오고 있기 때문이다.

아래는 해당 리퀘스트 내용이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /Schedule/cont/ajaxMovieSchedule.aspx HTTP/1.1
Host: m.cgv.co.kr
Connection: keep-alive
Content-Length: 36
Origin: http://m.cgv.co.kr
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: */*
Referer: http://m.cgv.co.kr/Schedule/?tc=0056&t=T&ymd=20170327&src=
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: .......
cs

(쿠키 정보는 임의로 지웠다.)



POST 메서드로 /Schedule/cont/ajaxMovieSchedule.aspx 라는 엔드포인트에 리퀘스트를 날리는 내용이다.

리퀘스트와 함께 날리는 폼 데이터를 확인해보면

1
2
3
theaterCd:0056
playYMD:20170327
src:
cs

아래오 같다. 


아까 분석한 결과와 비슷한걸 알 수 있는데,

theaterCd: 지점코드 (위에서 tc와 같다.)

playYMD: 상영목록을 확인할 날짜(위에 ymd와 같다)

src: 위와 같다.


자 저렇게만 리퀘스트를 맞춰 날려준다면 우리의 목적은 끝나게 된다.


간단하지 않은가? 

1
2
3
4
5
6
7
8
import requests
 
form = {
    'theaterCd''0056'
    'playYMD''20170327',
}
 
res = requests.post('http://m.cgv.co.kr/Schedule/cont/ajaxMovieSchedule.aspx', form)
cs


리퀘스트 보내는데 한줄이면 된다.

(물론 폼 데이터가 만들어져 있어야 되겠지만..)


필요한 재료는 다 갖춰졌고, 이제 파싱만 해주면 되는데,

파이썬의 유명한 파서 라이브러리인 BeautifulSoup을 사용하여 간단하게 파싱을 진행해보자.


공식 도큐먼트는 여기에서 확인 가능하다.



리스폰스로 받은 데이터의 구조를 간단하게 확인해보면

1
2
3
4
5
6
<ul class="timelist">
    <li>
        <a href="javascript:popupSchedule('제목','영화관 위치','상영시간','잔여좌석수','총좌석수', '영화코드', '', '상영날짜', 등등정보..." class="Btn_lightGrey">상영시간</a>
    </li>
    ...
</ul>
cs

li > a 로 각 영화들의 섹션을 나누고 있다.

자바스크립트를 호출하여 팝업을 보여주고 있으며, 인자로 해당 영화에 대한 정보를 보여주게 되어 있다.

그럼 우리의 목적은 ul.timelist 의 하위목록을 전부 가져와 제목과 상영시간을 가져와보도록 하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests
from bs4 import BeautifulSoup  # << 추가
 
form = {
    'theaterCd''0056'
    'playYMD''20170327',
}
 
res = requests.post('http://m.cgv.co.kr/Schedule/cont/ajaxMovieSchedule.aspx', form)
 
soup = BeautifulSoup(res.text, 'html.parser')  # << 추가
lst = soup.select('ul.timelist > li > a')  # << 추가
 
# lst에는 a태그들이 리스트로 담기게 된다.
lst[0]['href']    # href 를 가져온다.
lst[0].text        # 태그 안에 text를 
cs


아까 코드에 3줄만 추가 되었다.

lst에는 a태그의 리스트들이 담기게 되고


원하는 attribute에 접근할때에는 딕셔너리에 접근할때와 같이 사용하면 된다.

href 를 가져오게 되면 javascript 구문을 가져오게 될텐데, 해당 부분은 알아서 파싱하도록 하자..ㅠ




자 지금까지 크롤러 만들기 전에 필요한 간단 개념을 확인했는데,

이정도면 알고 있다면 왠만한 크롤링은 다 가능하다 볼 수 있다.


csrf 로그인 폼 통과라던가, 크롤러 블로킹 등을 우회해야 될때도 많은데 

기본적인 배경지식만 있다면 충분히 코드를 응용할 수 있으리라 믿는다.


이외에도 크롤러 속도를 높이기 위해서 mp를 사용한 병렬처리 등을 할 수 있는데,

직접 만들기 보단, scrapy 라는 크롤링 프레임워크가 존재하는데,

이런 잘만들어진 프레임워크나 라이브러리를 잘 활용하는게 더 속 편하다. (잘갖다 쓰는것도 능력..)

scrapy 도 굉장히 빠른 속도를 보여준다.


나중에 기회가 된다면 한번 포스팅을 해보도록 하겠다 !



Cross Origin Resource Sharing 이란 약자로 크로스 도메인 요청에 대한 표준이다.

정리가 잘 되어있는 블로그를 소개한다.

순서대로 읽어보면 이해가 빠를듯 싶다.

천천히 페이지를 정독하고 각각의 링크를 읽어보길 바란다.



http://blog.iolo.kr/494


'Programing > Web' 카테고리의 다른 글

[HTML5, JavaScript] Html5 Canvas 를 사용해 그림판 만들기  (1) 2017.01.28

+ Recent posts