-
네이버 쇼핑 아이디별 등록 상품 추출하는 법(파이썬 script 태그 스크래핑 가이드)코딩 연습/코딩배우기 2022. 1. 14. 13:09
네이버 쇼핑의 각 판매자 사이트에 들어가 보면 상품 리스트가 있고, 각 상품에 대한 제목, 가격, 리뷰수, 평점 등의 데이터가 있다. 이 부분을 확인해보면 <script> 태그 부분으로 되어있는데, 파이썬으로 이 부분을 스크래핑(크롤링)하는 방법을 설명하고자 한다.
파이썬 requests로 네이버쇼핑 아이디별 등록 상품 리스트 데이터 추출
네이버 쇼핑에서 상품 검색 시 스마트스토어에 상품을 등록한 판매자명이 보인다.
그 부분을 클릭하면 해당 판매자의 스마트스토어 쇼핑몰에 접속하게 되는데, 상품 리스트의 html 소스코드 내용을 보기 위해 "페이지 소스보기"를 해서 보던지, "개발자 도구(F12)"를 펼쳐 Name에서 메인 화면 또는 특정 항목(판매자 ID 등)으로 된 부분을 클릭해서 Response 부분의 코드를 보면 <script> 부분 밑에 관련 정보가 있는 것을 발견하게 된다.
개발자 도구 화면 <script>window.__PRELOADED_STATE__={"blogInfo":{"A":{"blogId":"","blogName" 부분으로 된 부분이 해당 판매자 쇼핑몰의 데이터들이 있는 태그이다.
import requests from bs4 import BeautifulSoup uid = '쇼핑 ID' url = f'https://smartstore.naver.com/{uid}' headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36', } r1 = requests.get(url, headers=headers) if r1.status_code == 200: soup = BeautifulSoup(r1.text, 'html.parser') scripts = soup.find('body').find_all('script') print(len(scripts)) cnt = 0 for script in scripts: print(f'cnt: {cnt}:\n{script.text}') cnt += 1
- script 태그를 requets와 BeautifulSoup로 파싱한 후 script 태그가 몇 개 있고, 몇 번째가 대상인지 확인하기 위한 코드이다.
- 그리고, 네이버이다 보니 headers 정보는 필히 넣어준다.
출력된 부분을 확인해보면 json 형식의 str 타입인데, window.__PRELOADED_STATE__= 부분을 삭제하기 위해 아래처럼 slice를 해준다.
data = scripts[0].text.strip()[27:] print(data[:200]) print('--------------------------') print(data[-100:])
- print(data[]) 부분은 잘 제거되었는지 확인하는 코드이다.
그런데, 잘 제거해졌다고 믿고 json()으로 str 전체를 불러오려고 했을 때, 오류가 발생했다.
json.decoder.JSONDecodeError: Expecting value: line 1 column 201 (char 200)
- decoder 문제인데, 구글에서 찾아보고 여러 방법을 시도했지만, 오류는 계속 발생했다.
저장해서 텍스트 파일을 열어봐도 문제는 없어 보였는데, 눈에 거슬리는 문자(🧡 💙 💚 💜 ❤)가 보였다.
with open('./data.txt', 'w', encoding='utf-8', errors='ignore') as f: f.write(data)
얼마 전에 이런 이모지 문자로 인해 어려움을 겪은 것이 떠올라서 해당 소스에서 이모지 문자를 제거하는 함수를 가져와서 추출된 data를 넣고 실행 후 리턴 값을 받아서 처리해봤다.
def remove_emoji(data): emoj = re.compile("[" u"\U0001F600-\U0001F64F" # emoticons u"\U0001F300-\U0001F5FF" # symbols & pictographs u"\U0001F680-\U0001F6FF" # transport & map symbols u"\U0001F1E0-\U0001F1FF" # flags (iOS) u"\U00002500-\U00002BEF" # chinese char u"\U00002702-\U000027B0" u"\U00002702-\U000027B0" u"\U000024C2-\U0001F251" u"\U0001f926-\U0001f937" u"\U00010000-\U0010ffff" u"\u2640-\u2642" u"\u2600-\u2B55" u"\u200d" u"\u23cf" u"\u23e9" u"\u231a" u"\ufe0f" # dingbats u"\u3030" "]+", re.UNICODE) return re.sub(emoj, '', data) data = remove_emoji(data) # 이모지 제거 r2 = json.loads(data) print(r2, type(r2)) # <class 'dict'>
- 이제 제대로 실행이 되었다. 문제가 된 부분이 바로 이것 떄문이었다.
추출된 data에서 "상품 전체" 부분만을 다시 정제하기 위해 json 포맷을 확인하는 사이트(https://jsonformatter.curiousconcept.com/)에서 돌려보니 아래와 같이 복잡한 구조로 되어있음을 확인했다.
script data의 json 구조 - 이 구조에서 어디 부분이 '상품 전체"인지 찾아보니 widgetContents 부분에 있었다.
dict 데이터에서 그 부분을 아래와 같이 for 문으로 필요한 부분만을 추출했다.
r2 = json.loads(data) # print(r2, type(r2)) # <class 'dict'> item_cnt = 0 itemsList =[] for dict_elem in r2['widgetContents']['wholeProductWidget']['A']['data']: # 상품전체 부분을 대상으로 함 name = dict_elem['name'] items ={ 'name': dict_elem['name'], 'id': dict_elem['id'], 'categoryId': dict_elem['category']['categoryId'], 'categoryName': dict_elem['category']['wholeCategoryName'], 'channelName': dict_elem['channel']['channelName'], 'productNo': dict_elem['productNo'], 'salePrice': dict_elem['salePrice'], 'productStatusType': dict_elem['productStatusType'], 'discountedSalePrice': dict_elem['benefitsView']['discountedSalePrice'], 'discountedRatio': dict_elem['benefitsView']['discountedRatio'], 'textReviewPoint': dict_elem['benefitsView']['textReviewPoint'], 'photoVideoReviewPoint': dict_elem['benefitsView']['photoVideoReviewPoint'], 'reviewCount': dict_elem['reviewAmount']['totalReviewCount'], 'averageReviewScore': dict_elem['reviewAmount']['averageReviewScore'], 'representativeImageUrl': dict_elem['representativeImageUrl'] } itemsList.append(items) item_cnt += 1 print(itemsList) print(item_cnt)
- dict인 items에 넣고, 다시 itemsList에 넣은 후, pandas 모듈을 사용해서 excel로 저장해 봤다.
df = pd.DataFrame(itemsList) print(df.head()) df.to_excel(uid + '.xlsx', index=False)
지난 11월에 requets와 BeautifulSoup의 다른 방법으로 네이버 쇼핑의 데이터를 가져오는 스크래핑을 해봤었는데, 이 방법이 더 좋은 것 같다.
이렇게 받은 데이터를 DB에 저장하는 방법은 여기 참고
'코딩 연습 > 코딩배우기' 카테고리의 다른 글
공공데이터를 활용한 아파트 도로명 주소 등 추출해보기 (0) 2022.01.18 웹 페이지 <script> 태그 CDATA, 넌 뭐하는 넘이니... (0) 2022.01.15 이미지 다운로드 관련 requests와 requests-html 비교 (0) 2022.01.11 동적(JavaScript) 웹 페이지의 json 데이터 형식 이미지 다운로드 (with 파이썬) (0) 2022.01.11 11번가 실시간 쇼핑 검색어 추출해서 저장하기(python tkinter) (0) 2022.01.10