python 으로 개발하면서 URL 을 다루게 되면서 어떻게 URL 내에서 path 만 가져와야하고 parameter 를 어떻게 가져와야하고 query string 은 어떻게 추가해야하는지에 대한 고민을 했던 적이 있다.
정말 단순하게 생각했을 때 URL 문자열 알에 들어있는 '/' 나 '?' 또는 '&' 등의 문자를 통해 split 해서 가져오면 되지 않을까? 하는 생각이 들었다. 하지만 python urllib 이라는 라이브러리를 통해서 정말 쉽게 URL 을 다룰 수 있다는 것을 알게 되었고 어떻게 사용할 수 있는지 정리해보려고 한다.
먼저 urllib 을 사용해보기 위해서 다음과 같이 URL 이 있다고 가정하고 사용해보려고 한다.
이 URL 은 내가 지금 블로그에 글을 쓰고 있는 페이지의 URL 이다.
https://jaynamm.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F#
이 URL 을 통해 python urllib 을 사용해보자.
해당 내용은 아래의 문서를 참고해서 작성했다.
https://docs.python.org/ko/3/library/urllib.parse.html#module-urllib.parse
urllib.parse 라는 모듈에 대해서 알아볼 예정이고
urllib.parse 는 URL(Uniform Resource Locator) 문자열을 구성요소로 분리하고 구성요소를 다시 URL 로 결합할 수 있게 제공해준다.
urllib.parse.urlparse
먼저 urlparse 에 대해서 알아보자.
urlparse 는 URL 을 6개의 구성요소로 구문을 분석해서 네임드 튜플을 반환한다.
여기서 named tuple 이란 쉽게 말해서 이름으로 접근이 가능한 튜플을 말한다.
각 tuple 은 문자열로 되어있고 비어있을 수도 있다.
구성 요소는 더 작은 부분으로 나뉘지 않고 % 이스케이프는 확장되지 않는다고 한다.
추가로 urlparse 인자로 scheme 와 allow_fragments 라는 값을 지정해줄 수 있다.
scheme 는 URL 이 지정하지 않은 경우에만 사용될 기본 주소 지정 채계를 제공한다고 한다.
기본 값으로 '' 가 항상 허용되고 필요하면 자동으로 b'' 로 변환된다는 점을 제외하고 urlstring 과 같은 타입이어야 한다.
그리고 allow_fragments 는 인자가 겆시이면 프래그먼트 식별자는 인식되지 않는다.
대신 path, parameters 또는 query 구성 요소의 일부로 구문이 분석되고 fragment 는 반환 값에서 빈 문자열로 설정된다고 한다.
마지막으로 반환 값은 네임드 튜플로 되어있고 다음과 같이 인덱스나 이름이 있는 속성으로 접근할 수 있다.
URL 에 잘못된 포트가 지정된 경우에는 port 속성값을 읽어올 때 ValueError 가 발생한다.
직접 사용해보면서 확인해보기로 하자.
>>> from urllib.parse import urlparse
>>> url = "https://jaynamm.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F#"
>>> urlparse(url)
ParseResult(scheme='https', netloc='jaynamm.tistory.com', path='/manage/newpost/', params='', query='type=post&returnURL=%2Fmanage%2Fposts%2F', fragment='')
결과를 확인해보면 다음과 같다.
- netloc='jaynamm.tistory.com'
- path='/manage/newpost/'
- params=''
- query='type=post&returnURL=%2Fmanage%2Fposts%2F'
- fragment=''
결과를 통해 원하는 path 나 query string 값을 가져와서 사용할 수 있다.
추가로 _replace() 메서드를 사용해서 지정된 필드를 새로운 값으로 대체해서 반환할 수 있다고 한다.
>>> urlparse(url)._replace(scheme='http')
ParseResult(scheme='http', netloc='jaynamm.tistory.com', path='/manage/newpost/', params='', query='type=post&returnURL=%2Fmanage%2Fposts%2F', fragment='')
결과와 같이 scheme 가 https 에서 http 로 변경되었다.
urllib.parse.parse_qs
그럼 결과에서 보여주는 query string 값이 다음과 같이 문자열로 주어졌다.
query='type=post&returnURL=%2Fmanage%2Fposts%2F'
결국에는 이렇게 주어진 query string 에서 특정 값을 가져오기 위해서는 문자열 처리를 통해 가져와야 한다.
따라서 urllib 에서는 parse_qs 를 통해 query stirng 값을 딕셔너리로 반환해준다.
직접 사용해보면서 결과를 확인해보자.
>>> from urllib.parse import urlparse, parse_qs
>>> url = "https://jaynamm.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F#"
>>> urlparse(url)
ParseResult(scheme='https', netloc='jaynamm.tistory.com', path='/manage/newpost/', params='', query='type=post&returnURL=%2Fmanage%2Fposts%2F', fragment='')
>>> urlparse(url).query
'type=post&returnURL=%2Fmanage%2Fposts%2F'
>>> parse_qs(urlparse(url).query)
{'type': ['post'], 'returnURL': ['/manage/posts/']}
결과를 보면 딕셔너리로 값이 반환된 것을 확인할 수 있었다.
urllib.parse.parse_qsl
또한 parse_qsl 을 통해 리스트로 반환할 수도 있다.
>>> from urllib.parse import urlparse, parse_qsl
>>> url = "https://jaynamm.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F#"
>>> urlparse(url)
ParseResult(scheme='https', netloc='jaynamm.tistory.com', path='/manage/newpost/', params='', query='type=post&returnURL=%2Fmanage%2Fposts%2F', fragment='')
>>> urlparse(url).query
'type=post&returnURL=%2Fmanage%2Fposts%2F'
>>> parse_qsl(urlparse(url).query)
[('type', 'post'), ('returnURL', '/manage/posts/')]
결과를 확인해보면 리스트 형태로 값이 반환된 것을 확인할 수 있었다.
urllib.parse.urlsplit
urlsplit 은 urlparse 와 유사하지만 URL 에서 파라미터를 분할하지 않는다. 따라서 5개의 네임드 튜플로 값을 반환한다.
urlsplit 의 반환값은 다음과 같다.
직접 사용해서 urlparse 와 결과가 어떻게 다른지 확인해봤다.
>>> from urllib.parse import urlsplit
>>> urlsplit(url)
SplitResult(scheme='https', netloc='jaynamm.tistory.com', path='/manage/newpost/', query='type=post&returnURL=%2Fmanage%2Fposts%2F', fragment='')
결과를 확인해보면
urlparse 의 결과는 아래와 같고
ParseResult(scheme='https', netloc='jaynamm.tistory.com', path='/manage/newpost/', params='', query='type=post&returnURL=%2Fmanage%2Fposts%2F', fragment='')
urlsplit 의 결과는 아래와 같다.
SplitResult(scheme='https', netloc='jaynamm.tistory.com', path='/manage/newpost/', query='type=post&returnURL=%2Fmanage%2Fposts%2F', fragment='')
차이점이라고하면 urlsplit 은 URL 의 파라미터를 분할하지 않기 때문에 그 차이를 확인할 수 있었다.
urllib.parse.urljoin
지금까지는 URL 을 가져와서 값을 parsing 해서 각각의 값들을 가져왔었는데 이번에는 url을 결합해보려고 한다.
urljoin 은 기본 URL 을 가져와서 다른 URL 과 결합하여 전체 URL 을 구성한다고 한다.
기본 URL 의 구성 요소, 특히 주소 지정 체계와 네트워크 위치 및 경로의 일부를 사용해서 상대 URL 에서 누락된 구성 요소를 제공해준다고 한다.
한번 사용해보면서 알아보자.
>>> from urllib.parse import urljoin
>>> url = "https://jaynamm.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F#"
>>> new = "urljoin.tistory.com"
>>> urljoin(url, new)
'https://jaynamm.tistory.com/manage/newpost/urljoin.tistory.com'
>>> new = "http://urljoin.tistory.com"
>>> urljoin(url, new)
'http://urljoin.tistory.com'
>>> new = "test"
>>> urljoin(url, new)
'https://jaynamm.tistory.com/manage/newpost/test'
3가지 정도로 해보았는데 new 에 입력되는 url 의 구성 요소에 따라 값이 변경되는 것으로 보인다.
앞서 설명에서 상대 URL (new) 에서 누락된 구성 요소를 제공해주기 때문에
1번 결과에서는 scheme, netlot, path 가 누락되었다고 해서 base url 에서 가져와서 추가해준 것으로 보이고
2번 결과에서는 누락된 구성요소가 없다고 생각해서 그대로 출력해준 것으로 보이고
마지막 결과에서는 1번과 마찬가지로 누락된 부분을 추가해준 것으로 보인다.
urllib.parse.quote
마지막으로 quote 를 사용해서 URL 에 특수 문자를 인용하고 문자들을 아스키코드로 인코딩해서 보여줄 수 있다.
직접 사용해보면서 확인해보자.
간단하게 예를 들어서 사용해보았다.
>>> from urllib.parse import quote
>>> url = "https://jaynamm.tistory.com/manage/새로운글생성"
>>> quote(url)
'https%3A//jaynamm.tistory.com/manage/%EC%83%88%EB%A1%9C%EC%9A%B4%EA%B8%80%EC%83%9D%EC%84%B1'
결과를 확인해보면 "새로운글생성" 이라는 문자가 인코딩된 값으로 URL 이 만들어진 것을 확인할 수 있다.
마무리!!
이렇게 python urllib 라이브러리을 사용해서 URL 을 다루어보게 되었는데 문자열 split() 을 사용해서 문자열을 처리하는 것보다 더 안정적이고 확실하게 URL 의 구성 요소들을 가져올 수 있기 때문에 이후 URL 을 다룰 수 있는 경험이 생긴다면 urllib 라이브러리를 사용하면 좋을 것 같다.
'프로그래밍 언어 > Python' 카테고리의 다른 글
Python vars() 함수 (0) | 2023.08.16 |
---|---|
Pydantic 이란 (0) | 2023.08.10 |
Python reduce() 함수 (0) | 2023.03.01 |
Python open() 내장 함수 (0) | 2023.03.01 |
Python Asterisk(*) (0) | 2023.02.28 |