셀레니움은 최후의 수단
저도 처음에 배울 때는 BeautifulSoup과 Selenium으로 입문했습니다.
사실 셀레니움이 직관적이고, 동적페이지 대응하기도 나름 편하고,
거의 웬만해서는 다 뚫기 때문에 많은 사람들이 쓰는 것 같습니다.
하지만 저는 소제목 그대로 최후의 수단으로 셀레니움을 선택합니다.
우선 태그 찾느라 HTML 처다보고 있는 것도 눈아프고,
인스타와 같이 제대로 관리하는 사이트는 정기적으로 태그명이 바뀌기 때문에
재사용성이 떨어지고, 무엇보다 스크랩 속도가 너무 느립니다.
구글링으로 쉽게 찾을 수 있는 크롤링 예시 중 하나인
스타벅스 매장 주소 스크랩을 예시로 보여드리겠습니다.
예상하기로는 해당 주소로 가서 F12로 inspector창 열어서 "서울", "경기", "광주"...이렇게 태그를 찾아서 Selenium으로
클릭하고, 클릭하고, 클래스 태그나 XPATH로 타고 들어가서 텍스트를 get 할 거라 짐작이 됩니다.
저희는 조금 다르게 접근해 보겠습니다.
우선 스타벅스에서 매장찾기 - 지역 검색 - 서울 까지는 접속을 합니다.
그리고 나서
1. 평소에 보던 Elements가 아닌 Network를 클릭
2. Fetch/XHR을 클릭
3. "전체"를 클릭합니다.
"전체"를 클릭하는 순간 Name창에 "getStore.do?r=LY2Z1HRZ39" 라는 이름이 하나 생성됩니다.
클릭해보면 옆에 Header Payload, Preview 등등이 생긴 것을 확인할 수 있습니다.
저희는 우선 Preview를 보겠습니다.
"Preview"를 클릭한 뒤 list 옆에 화살표를 클릭하면 뭔가 숫자 범위가 쭈~욱 있는 것을 확인할 수 있습니다.
마지막 번호 592가 무엇일까요??
네! 서울에 위치한 593번째(0부터 시작했으니) 매장 정보입니다.
화살표를 내려서 하위 항목을 보시면 매장 정보가 쭈욱 담겨 있는 것을 확인할 수 있습니다.
위도, 경도부터 시작해서 온갖 세세한 정보가 모두 포함되어 있는 것을 확인할 수 있습니다.
저는 백엔드를 공부하지 않아서 잘은 모르지만 변할 가능성이 있는(?) 데이터 즉 하드 코딩이 비효율적인 데이터는
보통 데이터 베이스에 저장해 두고서 API를 통해 그때 그때 가져오는 방식을 취합니다.
스타벅스 사이트도 제가 서울 전체 매장 정보를 호출하면 API로 정보를 당겨 오는 것으로 저는 이해하고 있습니다.
이제 저 데이터를 그대로 들고 올 수 있다면 좋겠죠?
이제 캡처 사진 없이 글로만 말씀드릴게요 잘 따라와 주세요
import requests
import json
# Header - General 에 있는 Requests URL 주소를 복사합니다.
url = "https://....."
# Payload에 있는 정보를 Dictionary 형태로 가져옵니다.
data = {
"ins_lat": 37.56682,
"ins_lng": 126.97865,
"p_sido_cd": "01", # 지역별 고유 번호임을 유추할 수 있습니다. 이 값을 for문으로 돌리면...
"in_biz_cd": "",
"p_gugun_cd": "",
"iend": 1000,
"searchType": "C",
"set_date": ""
}
# 하단의 Requests Header 창에서 아래 정보를 입력합니다.
header = {
"referer": "https://www.starbucks....."
"user_agent": "Mozilla/5.0....."
}
# requests뒤에 post를 쓸지 get을 쓸지는 General에 있는 Request Method를 참조합니다.
res = requests.post(url, data=data, headers=headers)
# print(res) 출력 시 <Response [200]>이 출력되면 성공
result = json.loads(res.text)
result
Jupyter notebook에서 위 코드에 빈칸을 작성하셔서 성공하시면 아래와 같은 내용을 확인할 수 있습니다.
너무 길어서 일부분만 가져왔지만 우선 Dictionary 형태인 것을 확인할 수 있습니다.
자세히 보시면 'list' 라는 key값에 리스트가 들어있고 그 안에 또 key, value 쌍이
들어있는 것을 확인하실 수 있습니다.
# 전체를 df로 변경 후 's_biz_code' 컬럼만 가져옵니다.
df = pd.DataFrame(result['list'])
df = df[['s_biz_code']]
df
사실 result에 담은 정보도 좋지만 각 매장 내 디테일한 정보도 조회할 수 있을 것 같아서
s_biz_code만 담았습니다. 이 정보는 확인해보니 매장 고유번호인 듯 했습니다.
이 정보와 연동해서 각 매장 상세 정보와 매칭하려고 합니다.
# 매장 상세 정보
url = "https://www.starbucks.co.kr/store/getStoreView.do"
data = {
'in_biz_cd': 3762 # 매장 고유 번호 하나를 가져왔습니다. 이것 역시 for문을 쓰면...
}
headers = {
'referer': 'https://www.starbucks.co.kr/',
'user-agent': '...',
}
res = requests.post(url, data=data, headers=headers)
store_detail = json.loads(res.text)
# 바로 df로 변환합니다. (원래는 json 파일부터 조회하세요)
store_detail_df = pd.DataFrame(store_detail['view'])
store_detail_df[['s_biz_code', 's_name', 'sido_name', 'gugun_name', 'doro_address',
'park_info', 'map_desc', 'notice', 'lat', 'lot']]
이렇게 고유번호와 연결하면 쉽고 편리하게 매장 정보를 골라서 가져올 수 있습니다.
처음 코드를 보시면 잘 이해가 안가실 거라 생각합니다.
코드를 한줄 한줄 실행해 보시는 것을 추천드리고,
Network를 자주 들여다 보셔서 json에 익숙해 지시는 걸 추천드립니다.
마지막으로 매장 정보를 가져오는데 속도가 어느정도인지 확인해 보겠습니다.
전국 스타벅스 매장 1746곳의 매장 고유 번호를 가져오는데 39초,
고유 번호와 매칭한 매장 정보를 가져오는데 약 3분 정도 걸렸습니다.
'파이썬 코딩 한줄' 카테고리의 다른 글
키워드를 활용한 간단한 제품 추천 컨텐츠 기반 필터링(CBF) (0) | 2022.10.18 |
---|---|
[pandas apply] 텍스트를 일정 길이만큼 잘라서 분리하기 (0) | 2022.10.14 |
파이썬 groupby로 요소 모아 보기 (단순 집계 이상으로 활용하기) (0) | 2022.09.21 |
이미지 URL에서 이미지 파일 다운받기 (0) | 2022.09.16 |
파이썬 print와 return의 차이가 헷깔리는 이유는? (0) | 2022.02.26 |