카테고리 없음
230223_DB복습
보랏
2023. 2. 23. 21:50
안녕하세요. 보랏입니다.
오늘은 GS25, 세븐일레븐, 이마트24홈페이지를 크롤링하여
전국 매장 수, 매장별 편의시설 등을 확인하였습니다.
바로 복습 시작하겠습니다.
1. GS25
- gs25의 홈페이지는 CSRF 토큰값으로 만들어져 있어 해당 토큰값을 돌려 API를 요청해야하는 Session입니다. 그래서 우선 토큰값을 돌릴 수 있는 변수를 설정해야 합니다.
- CSRF : 사용자의 의도와 관계 없이 행해지는 공격방법
- CSRF Token
- 임의의 난수를 생성하고 Session에 저장, 그리고 사용자의 매 요청마다 해당 난수 값을 포함시켜 전송하는 방법
- 이후 백엔드에서 요청을 받을 때마다 Session에 저장된 토큰값과 요청 파라미터에 전달된 토큰값이 같은지 검사
- Session
- 웹 사이트에 접근하고자 할 때 사용자 인증 필요, 접근 제한, 상태정보가 저장되어 있는 경우에 사용
- HTTP요청과 응답 사이에 유지되는 상태정보를 저장할 수 있는 기능
import requests
from bs4 import BeautifulSoup as BS
import json
import pandas as pd
url = "http://gs25.gsretail.com/gscvs/ko/store-services/locations"
payload = {"pageNum" : "1",
"pageSize" : "100",
"searchShopName" : "",
"searchSido" : "11",
"searchGugun" : "",
"searchDong" : "",
"searchType" : "",
"searchTypeService" : "0",
"searchTypeToto" : "0",
"searchTypeCafe25" : "0",
"searchTypeInstant" : "0",
"searchTypeDrug" : "0",
"searchTypeSelf25" : "0",
"searchTypePost" : "0",
"searchTypeATM" : "0",
"searchTypeWithdrawal" : "0",
"searchTypeTaxrefund" : "0",
"searchTypeSmartAtm" : "0",
"searchTypeSelfCookingUtensils" : "0",
"searchTypeDeliveryService" : "0",}
# CSRFToken 값 format으로 돌리기 위해 설정
post_url = "http://gs25.gsretail.com/gscvs/ko/store-services/locationList?CSRFToken={}"
#지역명, 지역코드를 딕셔너리 형태로 변경
master = {x.text : x['value'] for x in bs.find("select", id = "stb1").findAll("option")[1:]}
# 지역코드를 반복하여 얻은 지역별 gs25편의점의 데이터를 json형태로 total리스트에 추가
total = []
with requests.Session() as s :
r = s.get(url)
bs = BS(r.text)
csrf = bs.find("form", id = "CSRFForm").find("input")["value"] #gs25는 csrf토큰 값이 있어 해당 토큰 값으로 요청하기 위해 변수 생성 필요
for code in master.values() :
payload['pageSize'] = 5000
payload['searchSido'] = code
r2 = s.post(post_url.format(csrf), data = payload)
total.append(pd.DataFrame(json.loads(r2.json())['results']))
gs = pd.concat(total)
gs
- 이제 gs25의 지역별 점포 개수, offeringService중 drug을 보유한 편의점 확인 등을 진행하였습니다.
# 주소별 '시' 도출을 위해 split으로 분리
gs['시'] = gs['address'].apply(lambda x : x.split()[0])
# 지역별 점포 개수
gs['시'].value_counts()
2. 세븐일레븐 점포 크롤링
- 세븐일레븐도 gs25와 같이 지역별 점포 개수 등의 정보를 크롤링하였습니다. 그런데 세븐일레븐 홈페이지는 GS25보다 좀 더 까다롭게 되어 있어 selenium, requests, BeautifulSoup모두 사용하였습니다.
- 우선 각 시도별 지역명 변수를 생성하여 딕셔너리에 담는 코드입니다.
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
from bs4 import BeautifulSoup as BS
import requests
import re
import pandas as pd
# option 숨기기
options = webdriver.ChromeOptions()
options.add_argument('headless')
driver = webdriver.Chrome()
url = "https://www.7-eleven.co.kr/"
driver.get(url)
target_store = ""#header > div > div > div.head_util > a.util_store.store_open"
driver.find_element(By.CSS_SELECTOR, target_store).click()
time.sleep(3)
#시군 데이터 딕셔너리로 생성
city_dict = {}
for x in range(2,19) :
driver.find_element(By.CSS_SELECTOR, f"#storeLaySido > option:nth-child({x})").click()
time.sleep(3)
city = drvier.find_element(By.CSS_SELECTOR, f"#storeLaySido > option:nth-child({x})").text
city_dict[city] = [x.text for x in BS(driver.page_source).find("select", id="storeLayGu")][3::2]
for key, value in city_dict.items()
print(key, value)
- 다음은 페이지를 넘어가면서 지역별 지점에 대한 정보를 얻는 코드입니다. 지금 저도 작성하면서 아직 이해가 안가는 부분이 있어서 다시 공부해야될 거 같아요...
def api_seven(page) :
seven = BS(page)
seven_total = []
for tmp in seven.find("div", class_ = 'list_store").findAll("li") :
seven_dict = {}
seven_dict['offeringService'] = [x['alt'] for x in tmp.findAll("img")]
seven_dict['shopName'] = tmp.find("span").text.strip()
try :
seven_dict['address'] = ' '.join(tmp.findAll('span')[-2].text.split()
expect :
return[]
if len(seven_dict['address']) < 2 :
seven_dict['address'] = ' '.join(tmp.findAll("span")[-3].text.split())
-, lat, lon = re.findall("(?<=\().+(?=\))", tmp.find('a')['href'])[0].split(",")
seven_dict['longs'] = lon
seven_dict['lat'] = lat
seven_total.append(seven_dict)
return pd.DataFrame(seven_total)
seven_url = "https://www.7-eleven.co.kr/util/storeLayerPop.asp"
payload = {"storeLaySido": "서울",
"storeLayGu": "구로구",
"hiddentext": "none"}
r= requests.post(seven_url, data=payload)
#api시작
total = []
for key, value in city_dict.items():
print(key)
payload['storeLaySido'] = key
for x in value:
payload['storeLayGu'] = x
total.append(api_seven(requests.post(seven_url, data=payload).text))
오늘은 이렇게 블로그는 마치고,
다시 코드별로 공부를 해보려고 합니다.
오늘 뮤즈출시인데 공부해야하다니...
감사합니다.