웹 스크래핑을 위한 기초적인 지식으로 HTTP의 기본 개념들에 대해 공부하고, 파이썬의 urllib
라이브러리를 사용하는 방법에 대해 정리해 보았습니다. 아래서 정리한 것들은 realpython.com의 내용들을 위주로 한 것들입니다.
HTTP GET 요청은 서버에 특정 리소스를 요청하는 가장 기본적인 방법입니다. 클라이언트가 GET 요청을 할 때, 클라이언트는 서버로부터 정보를 가져오고자 할 뿐 서버의 상태를 변경하지 않습니다.
?
다음에 키-값 쌍으로 구성됩니다.웹 검색을 할 때, 검색 엔진에 입력한 쿼리는 GET
요청의 일부로 전송됩니다. 예를 들어, 구글에 "python tutorial"을 검색한다면, 브라우저는 다음과 같은 형태의 URL로 GET
요청을 보냅니다:
https://www.google.com/search?q=python+tutorial
여기서 q
는 쿼리스트링의 키이고, python+tutorial
은 사용자가 입력한 검색어의 값입니다.
HTTP POST
요청은 클라이언트에서 서버로 데이터를 보내 서버 상의 자원을 생성하거나 업데이트하기 위해 사용되는 메서드입니다. POST
요청은 데이터를 서버에 제출할 때 주로 사용되며, 이 때 데이터는 요청의 본문(body)에 포함됩니다.
POST
요청은 GET
요청에 비해 훨씬 큰 데이터를 보낼 수 있습니다. 데이터는 메시지 본문에 포함되므로 URL 길이에 대한 제약을 받지 않습니다.GET
보다 안전합니다. 그래서 로그인 정보와 같은 민감한 데이터를 전송할 때 자주 사용됩니다.POST
요청이 사용됩니다.POST
를 사용합니다.urllib.request
모듈에 있는 urlopen
함수는 URL을 열기 위해 사용되며, 이를 통해 웹 페이지의 내용을 가져올 수 있습니다. 이 함수는 기본적으로 HTTP GET 요청을 실행하고, 이에 대한 응답을 HTTPResponse
객체로 반환합니다.
from urllib.request import urlopen
response = urlopen('http://example.com/')
urlopen
함수는 데이터 인자가 제공될 경우 자동으로 HTTP POST 요청을 수행합니다. 데이터는 바이트 스트림으로 인코딩되어야 합니다.
from urllib.request import urlopen
from urllib.parse import urlencode
data = urlencode({'key1': 'value1', 'key2': 'value2'}).encode()
response = urlopen('http://example.com/', data=data)
urlopen
함수가 반환하는 HTTPResponse
객체는 서버의 응답을 나타냅니다. read()
메서드 등을 사용하여 응답의 본문을 읽을 수 있습니다. HTTPResponse 객체는 메타데이터(헤더)와 body로 이뤄져 있습니다. HTTPResponse 객체의 info() 메서드를 호출하면 HTTPMessage 객체가 반환됩니다. HTTPMessage 객체는 헤더를 나타내며, 헤더의 이름과 값을 조회할 때 사용합니다.
read()
: 응답의 본문을 읽습니다.getheader(name)
: 특정 헤더의 값을 반환합니다.getheaders()
: 모든 HTTP 헤더를 반환합니다.status
: HTTP 응답 코드를 나타냅니다. 예: 200, 404 등.content = response.read() # 본문 읽기
content_type = response.getheader('Content-Type') # 특정 헤더 값 가져오기
응답 객체를 사용한 후에는 close()
메서드를 호출하여 리소스를 해제하는 것이 좋습니다.
response.close()
하지만 with
를 이용하면 별도로 리소스를 해제하는 걸 신경 쓰지 않아도 됩니다.
with urlopen(url) as response:
body = response.read()
with의 scope를 벗어나면 자동으로 리소스가 해제됩니다.
응답 헤더에서 Content-Type
과 같은 메타데이터를 확인할 수 있습니다. 이는 인코딩 타입을 결정하거나 데이터의 형식을 파악하는 데 필요합니다. 접근하는 방식은 여러가지가 있습니다.
print('Content-Type : ', response.getheader('Content-Type')) # HTTPResponse의 메서드 사용
print('Content-Type : ', header.get('Content-Type')) # HTTPMessage의 메서드 사용
print('Content-Type : ', header['Content-Type']) # 헤더 객체를 딕셔너리처럼 접근
응답 본문(body)은 바이트 형태로 되어 있으며, read()
메서드를 통해 접근할 수 있습니다. 대체로 웹스크래핑을 위한 데이터는 바디에 위치합니다. 앞서 설명한대로, 응답 객체에 대해 .read()
를 사용해서 바디에 접근할 수 있습니다.
body = response.read()
여기서 body를 출력하면 b'로 표시되는 바이트 형태입니다. 이를 문자열로 변환하기 위해서는 적절한 디코딩이 필요합니다.
대부분의 웹은 'utf-8'을 사용해 문자열을 인코딩할 수 있습니다. 하지만 다른 형식을 사용하는 경우도 있을 수 있습니다. 이를 위해 정확한 인코딩 형식을 확인하는 것이 좋습니다. 이를 위한 정보는 헤더에서 찾을 수 있습니다.
from urllib.request import urlopen
url = 'https://www.google.com'
with urlopen(url) as response:
body = response.read()
char_set = response.headers.get_content_charset()
# 인코딩이 명시되지 않았을 경우 utf-8을 기본값으로 사용
if char_set is None:
char_set = 'utf-8'
print('Decoded Character Set: ', char_set)
decoded_body = body.decode(char_set)
urlopen
으로부터 반환된 응답 객체의 headers
속성을 통해 적절한 인코딩 타입을 찾아냅니다. get_content_charset()
메서드를 사용하여 Content-Type
헤더에서 올바른 문자 인코딩 형식에 대한 정보를 얻습니다. 만약 인코딩이 명시되어 있지 않다면, 대부분의 웹 페이지에서 사용하는 'utf-8'을 기본값으로 사용합니다.
응답 본문은 바이트(byte) 형태로 있기 때문에, 이를 문자열로 변환하기 위해 decode()
함수를 사용합니다. 이 함수에 인코딩 타입을 전달하여 데이터를 적절하게 디코딩합니다.
print('Body : \n', decoded_body[:50])
디코딩된 본문의 첫 50자를 출력하여 디코딩이 제대로 되었는지를 간단히 확인할 수 있습니다.
이러한 과정을 통해, 웹 스크래핑을 할 때 서버로부터 얻은 원시 데이터(raw data)를 적절한 형식으로 변환하고 사용할 준비를 할 수 있습니다. 다음으로는 이 디코딩된 데이터를 파일에 쓰는 방법을 살펴보겠습니다.
웹 스크래핑을 통해 가져온 데이터를 파일에 저장하는 것은 매우 흔한 작업입니다. 분석을 위한 데이터를 수집하고 보관할 수 있습니다.
# 디코딩된 텍스트 데이터를 HTML 파일로 저장
with open('./output/google.html', encoding='utf-8', mode='w') as file:
file.write(decoded_body)
위 예제에서는 open
함수를 사용하여 'output/google.html' 파일을 'w' 모드(쓰기 모드)로 엽니다. 파일이 존재하지 않으면 새로 생성되고, 이미 있다면 내용을 덮어쓰게 됩니다. 'encoding' 매개변수는 파일이 저장될 때 사용할 인코딩을 지정합니다. 여기서는 'utf-8'을 사용했으나, 다른 인코딩이 필요하다면 이를 적절히 변경해야 합니다.
# 저장된 HTML 파일을 읽어서 내용 확인
with open('./output/google.html', encoding='utf-8', mode='r') as file:
lines = file.readlines()
print('+' * 40)
print('First few lines of the file:', lines[:5])
파일을 'r' 모드(읽기 모드)로 열고 readlines()
메서드를 사용하여 파일의 모든 줄을 읽어 리스트로 반환합니다. 이 리스트에서 첫 5줄만 출력하여 저장된 데이터가 올바른지 검증할 수 있습니다.
이 방법을 사용하여 웹 페이지의 HTML을 파일로 저장하고, 필요에 따라 추가 작업을 수행할 수 있습니다. 데이터를 파일로 저장함으로써 나중에 다시 웹 서버에 접근하지 않고도 분석이나 다른 작업을 할 수 있습니다.
따로 인코딩을 하지 않고 바이트 객체를 그대로 파일로 저장할 수도 있습니다.
with open('./output/google.html', mode='wb') as file:
file.write(body)
웹 스크래핑으로 가져온 데이터를 텍스트로 변환하지 않고 바이트 형태로 직접 파일에 저장할 수도 있습니다. 특히 이미지, 동영상 파일, PDF 문서 등 바이너리 형태의 데이터를 다룰 때 유용합니다.
body
가 바이트 객체로 존재할 때 그대로 파일에 쓰기를 하고 있습니다.여기서는 open
함수를 사용할 때 파일 모드를 'wb'로 설정합니다. 'w'는 쓰기 모드를, 'b'는 바이너리 모드를 나타냅니다. 바이너리 모드에서는 파일에 데이터를 바이트 단위로 쓸 수 있으며, 이 경우 인코딩을 지정할 필요가 없습니다.
이 방법을 사용하면, 원본 데이터를 변경하지 않고 정확하게 같은 형태로 파일에 저장할 수 있습니다. 나중에 이 파일을 다시 바이트로 읽어들여 처리하거나, 웹 브라우저에서 직접 열어볼 수도 있습니다.