scrape.py

Ka-Ping Yee

scrape.py는 웹페이지에서 웹소를 긁어 오기 위한 파이썬 모듈이다. 손쉽게 페이지를 가져올 수 있고, 링크를 따라가고, 폼을 제출할 수 있다. 쿠키와 방향전환 그리고 SSL은 자동으로 처리된다. (SSL을 위해서는 파이썬에 socket.ssl 함수가 갖추어져 있거나, curl 명령-줄 유틸리티가 있어야 한다.)

scrape.py는 페이지를 완전하게 해석 트리로 바꾸지 않는다. 그래서 느슨하게 페이지를 다룰 수 있다. 마음대로 근처의 텍스트나 태그 또는 주석에 맞게 웹소를 찾을 수 있다.

모듈을 내려받거나 또는 문서 페이지를 읽어 보실 수 있다. 이 코드는 GNU 일반 공개 라이센스 버전 2 아래에서 배포된다.

다음에 간략하게 소개한다.

웹 페이지 가져오기

페이지를 가져오려면, go(url) 메쏘드를 Session 객체에 사용하면 된다. 이 모듈은 기본 세션 객체를 s라는 변수에 제공한다.

>>> from scrape import *
>>> s.go('http://zesty.ca/')
<Region 0:17780>

결과는 Region 객체로서 열람된 전체 문서를 아우른다 (모두 17780 바이트). Region 객체는 HTML 문서 안을 돌아다니는데 사용한다; Region 객체는 HTML 소스 코드에서 시작 지점과 끝 지점으로 텍스트 구역을 나타낸다.

성공적으로 가져오면, 세션의 doc 속성도 그 문서를 보유한다. headers 속성에는 수신된 헤더들이 담기며, url 속성에는 수신된 URL이 담긴다 (이 값들은 방향전환이 일어나면 요청한 URL과 다르다.).

>>> s.doc
<Region 0:17780>
>>> s.headers
{'date': 'Sat, 05 Jul 2008 11:25:04 GMT',
 'accept-ranges': 'bytes',
 'content-type': 'text/html; charset=UTF-8',
 'connection': 'close',
 'server': 'Apache/2.0.46 (Red Hat)'}
>>> s.url
'http://zesty.ca/'

Region 객체에서, 날 웹소는 content 속성에서 얻을 수 있고 평범한 텍스트는 text 속성에서 얻을 수 있다. (이 경우, 둘 모두 유니코드 문자열이다. 유니코드 인코딩을 서버에서 지정했기 때문이다.)

>>> d = s.doc
>>> print d.content[:70]
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
<html
>>> d.text[:30]
u'Ka-Ping Yee\nKa-Ping Yee pingze'

웹소 추출하기

Region 객체는 마치 문자열처럼 조각썰기가 가능하다. 이 객체는 원래 문서에서 시작 위치와 끝 위치를 기억한다. 그러나 공급된 지표는 무엇이든 그 구역 자체에 관련되어 있다.

>>> d
<Region 0:17780>
>>> r = d[1400:1450]
>>> r
<Region 1400:1450>
>>> len(r)
50
>>> r.start
1400
>>> r.end
1450
>>> r.content
u'd voting system security.\nOr check out my\n<a href='
>>> r[-15:]
<Region 1435:1450>

지정한 태그 이름의 시작 태그와 끝태그에 부합하는 첫 블록을 (구역 안에서) 찾으려면 first(tagname)Region 객체에 요청하자. 결과 Region 객체에 그 태그에 관한 정보가 유지된다; 사전 스타일로 속성에 접근할 수 있다. 구역은 시작 태그 바로 다음에서 시작하여 끝 태그 바로 앞에서 끝난다.

>>> t = d.first('title')
>>> t
<Region 247:258 title>
>>> t.tagname
'title'
>>> t.text
u'Ka-Ping Yee'
>>> s = d.first('span')
>>> s
<Region 2212:2213 span class='flag'>
>>> s.keys()
['class']
>>> s['class']
'flag'

last(tagname)은 구역 안에서 마지막 블록을 찾는다; next(tagname)은 구역의 끝 바로 다음에 시작하는 첫 블록을 찾는다; 그리고 previous(tagname)은 구역의 시작 바로 앞에서 끝나는 블록을 찾는다.

기본 탐색법

링크 앵커의 정확한 텍스트를 알고 있다면, follow(anchor)는 그 링크를 찾아서, 해석한 다음, 그를 따라간다. 홈페이지에 "CV"라는 링크가 있다면,

>>> s.follow('CV')
<Region 0:19843>
>>> s.headers
{'date': 'Sat, 05 Jul 2008 11:25:04 GMT',
 'accept-ranges': 'bytes',
 'content-type': 'text/html; charset=UTF-8',
 'connection': 'close',
 'server': 'Apache/2.0.46 (Red Hat)'}
>>> s.url
'http://zesty.ca/cv.html'
>>> s.doc
<Region 0:19843>
doc 속성은 열람된 문서를 보유한다 (go()submit() 또는 follow()도 같은 것을 돌려준다.).

정확한 앵커 텍스트 대신에, 정규 표현식을 앵커로 공급할 수 있다. 본인의 CV에 Waterloo 대학으로 가는 링크가 있지만, 텍스트가 정확하게 "Waterloo"는 아니다. 그렇지만 "Waterloo"로 끝나는 것은 확실하다.

>>> s.follow('Waterloo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/ping/python/scrape.py", line 243, in follow
    raise ScrapeError('link %r not found' % anchor)
scrape.ScrapeError: link 'Waterloo' not found
>>> s.follow(re.compile('.*waterloo', re.I))
<Region 0:10851>

back()을 호출하면 다시 CV 페이지로 돌아온다.

>>> s.url
'http://www.uwaterloo.ca/'
>>> s.doc
<Region 0:10851>
>>> s.back()
'http://zesty.ca/cv.html'
>>> s.doc
<Region 0:10851>

Region 객체는 HTML 요소와 연루시킬 수 있다. 이 경우 시작점은 그냥 시작 태그 바로 뒤이고 끝 지점은 끝 태그 바로 앞이다; 또는 개별 태그에 연루시킬 수 있다. 이 경우 시작 점은 "<" 바로 앞이고 끝 지점은 ">" 바로 뒤이다.

>>> from scrape import *
>>> s.go('http://zesty.ca/')
<Region 0:17780>