파이썬의 parse_qsl 함수는 URL 쿼리 문자열을 파싱하여 키-값 쌍의 리스트로 반환하는 유용한 도구입니다. 이 함수는 urllib.parse 모듈에서 제공되는데 파이썬의 장점의 깔끔한 코딩을 할 수 있도록 도와주는 함수입니다. 근데 만일 이걸 사용안하고 코딩을 한다면 어떻게 될까요? 어떤 원리로 parse_qsl은 작동하는지 알아보도록 하겠습니다.
먼저 예를 하나 보여드리겠습니다. url을 보면 GET방식으로 데이터를 호출하면 Query String값이 bbsno=30&no=310과 같이 문자열 형태로 이루어져 있어서 urllib.parse에는 query string을 파싱해서 collection으로 반환해주는 parse_qs와 parse_qsl 함수가 있습니다.
from urllib.parse import urlparse, parse_qs, parse_qsl
link="https://mydomain.com?bbsno=30&no=310&sort=name"
url_params = urlparse(link)
print(parse_qs(url_params.query))
# {'bbsno': ['30'], 'no': ['310'], 'sort': ['name']}
print(parse_qsl(url_params.query))
#[('bbsno', '30'), ('no', '310'), ('sort', 'name')]
# parse_qs 요소 분리
qs1 = dict(parse_qs(url_params.query))
# parse_qs의 결과를 dictionary로 캐스팅
bbsno1=qs1['bbsno']
no1=qs1['no']
#value값이 리스타로 들어옴
print("bbsno1:"+bbsno1[0]+",no1:"+no1[0]) #bbsno1:30,no1:310
# parse_qsl 요소 분리
qs = dict(parse_qsl(url_params.query))
# parse_qsl의 결과를 dictionary로 캐스팅
bbsno=qs['bbsno']
no=qs['no']
print("bbsno:"+bbsno+",no:"+no) #bbsno:30,no:310
위와같이 결과를 얻을 수 있는데 먼저 parse_qs와 parse_qsl 의 차이를 알아보도록 하겠습니다.
parse_qs는 key에 대해 value들을 list로 묶어서 dictionary로 반환합니다. 반면 parse_qsl은 key-value pair 각각을 tuple로 만들어서 list로 반환한다는 차이가 있습니다. 사용법도 살짝 다르지만 query string의 key가 표준에 의해서 중복이 허용되기 때문에 문제가 발생할 수 있습니다.
from urllib.parse import urlparse, parse_qs, parse_qsl
#no 값이 두개가 있는 경우
link="https://mydomain.com?bbsno=30&no=310&sort=name&no=900"
url_params = urlparse(link)
print(parse_qs(url_params.query))
#{'bbsno': ['30'], 'no': ['310', '900'], 'sort': ['name']}
print(parse_qsl(url_params.query))
#[('bbsno', '30'), ('no', '310'), ('sort', 'name'), ('no', '900')]
# parse_qs 요소 분리
qs1 = dict(parse_qs(url_params.query))
# parse_qs의 결과를 dictionary로 캐스팅
bbsno1=qs1['bbsno']
no1=qs1['no']
#value값이 리스타로 들어옴
print("bbsno1:"+bbsno1[0]+",no1:"+no1[0]) #bbsno1:30,no1:310
# parse_qsl 요소 분리
qs = dict(parse_qsl(url_params.query))
# parse_qsl의 결과를 dictionary로 캐스팅
bbsno=qs['bbsno']
no=qs['no']
print("bbsno:"+bbsno+",no:"+no) #bbsno:30,no:900
query string을 보면 no 값이 310과 900이렇게 두개가 있습니다. 이럴때 쿼리 param이 중복되었을때는 제일 나중에 온 값으로 서버에서는 인식하기 때문에 900이 정상입니다. 하지만 parse_qs를 사용하면 리스트의 첫번째 값인 310을 조회하고 parse_qsl를 사용하면 정상적으로 900이 찍히는것을 볼 수 있습니다. 왜냐면 parse_qsl은 중복 키를 허용하며, 동일 키의 모든 값을 반환하기 때문입니다.
아주 간단하게 깔끔하게 정리된것을 볼 수 있습다. 그렇다면 어떤 원리고 이렇게 처리가 가능한것일까요?
간단하게 parse_qsl을 사용하지 않고 주어진 URL에서 쿼리 문자열을 직접 파싱하는 것입니다. URL에서 쿼리 문자열을 추출하고 &와 =로 나누어 키-값 쌍을 처리해서 결과값을 가져오면 됩니다. 다음 소스를 보시겠습니다.
from urllib.parse import urlparse, parse_qs, parse_qsl
def user_query_parser(url):
# '?'를 기준으로 쿼리 문자열 추출
if '?' in url:
query_string = url.split('?', 1)[1] # '?' 이후의 문자열
else:
query_string = ''
# 결과를 담을 리스트
parsed_result = []
# '&'로 분리하여 키-값 쌍 나누기
pairs = query_string.split('&')
for pair in pairs:
if '=' in pair:
key, value = pair.split('=', 1) # '='로 분리
else:
key, value = pair, '' # 값이 없는 경우 빈 문자열 처리
# URL 디코딩
key = decode_url(key)
value = decode_url(value)
# 결과 추가
parsed_result.append((key, value))
return parsed_result
def decode_url(value):
"""URL 디코딩: %xx 형식을 변환"""
import urllib.parse
return urllib.parse.unquote(value)
link="https://mydomain.com?bbsno=30&no=310&sort=name&no=900"
parts = urlparse(link)
print(parse_qsl(parts.query)) # [('sort', 'name'), ('keyword', 'planb')]
parts = urlparse(link)
# 요소 분리
qs = dict(parse_qsl(parts.query))
# parse_qsl의 결과를 dictionary로 캐스팅
bbsno=qs['bbsno']
no=qs['no']
print("bbsno:"+bbsno+",no:"+no) #bbsno:30,no:900
print("#############################")
parsed_result1 = user_query_parser(link)
print(parsed_result1)
bbsno_next=qs['bbsno']
no_next=qs['no']
print("bbsno_next:"+bbsno_next+",no_next:"+no_next) #bbsno_next:30,no_next:900
결과는 아래와 같이 동일한 데이터임을 확인할 수 있습니다.
단순하게 url을 split을 잘 사용해서 데이터를 리스트로 변환해서 가져오면 됩니다. 파이썬의 장점을 저는 깔끔한 코딩과 개발자가 고민해야 할 부분을 거의 모든것을 함수화 시켰다는것이라 봅니다. 파이썬으로 개발자의 능력치를 키워보세요
같이보면 좋은 글
'정보마당' 카테고리의 다른 글
2024 BTOB 콘서트 일정 및 티켓 예매 정보 안내 (1) | 2024.11.23 |
---|---|
중고 노트북 구매 시 꼭 피해야 할 실수 총정리 (1) | 2024.11.20 |
[파이썬] YES24티켓 오픈일 순 정보 추출해서 엑셀로 저장 (1) | 2024.11.19 |
2025 슈퍼주니어 예성 콘서트 일정 및 티켓 예매 정보 안내 (0) | 2024.11.18 |
프롬 단독 콘서트 Arrival on the moonbow 일정 및 티켓 예매 정보 안내 (1) | 2024.11.16 |