본문 바로가기

IT/개발자

쇼핑몰 실시간재고 알림 봇 만들기 (1.파이썬 웹 크롤링 + BeautifulSoup)

반응형

회사에서 이번에 조조타운 1만엔 쿠폰을 줘서 사고 싶은 물건을 찾아보고 있는데, 사고 싶었던 물건이 매진이되서 1시간 마다 조조타운에서 재고가 있는지 없는지 확인해 주는 프로그램을 만들어 보았다.

 

저는 파이썬 개발자도 아니고, 처음으로 파이썬으로 개발을 해본거라 엄청 간단하게 만들었으니, 더 효율적인 방법이나 간단한 방법이 있으시면 말씀해 주시면 감사하겠습니다.

 

 

 

결과물

쇼핑몰 실시간재고 알림 봇 만들기(결과물 : 텔레그램 봇)

 

 

최종 코드는 아래와 같다. 아주 간단하다.

# 라이브러리 불러오기
import requests
# 1. 웹 크롤링 용 모듈
from bs4 import BeautifulSoup
# 2. 텔레그램 메세지 용 모듈
import telegram
# 3. 1시간 마다 반복하기 위한 스케쥴러 용 모듈
from apscheduler.schedulers.blocking import BlockingScheduler

chat_id = '$my_id' #메세지를 받으실 본인의 텔레그램 아이디값을 넣어주시면 됩니다.
token = '$my_token' #텔레그램 봇에서 받으신 토큰정보 입력하시면 됩니다.
bot = telegram.Bot(token=token)
sched = BlockingScheduler()

def extract_links():
    url = 'https://paypaymall.yahoo.co.jp/store/zozo/item/51309849/?subcode_img=849/52309849/52309849b_18_d&img_type=z&subcode=GDID82867651'
    req = requests.get(url)
    html = req.text
    # 해당 url의 html문서를 soup 객체로 저장
    soup = BeautifulSoup(html, 'html.parser')
    search_result = soup.select('li.ItemStockFKU_item')

    stocks = []

    for i in search_result:
        color = i.select('span.ItemFKU_text')[0].text
        value = i.select('span.Icon')[0].attrs['class'][1]
        if(value=='Icon-radioOff'):
            stocks.append(color + ". 재고 있음")
        elif(value=='Icon-close'):
            stocks.append(color + ". 재고 없음")
        else:
        	stocks.append(color + ". site확인 요 : "+ url)
	
    #telegram
    bot.sendMessage(chat_id=chat_id, text=url)
    for stock in stocks:
        bot.sendMessage(chat_id=chat_id, text=stock)

#스케줄러 돌리기 전, 한번 시작하기
extract_links()
#스케줄러 이용해서 한시간 마다 반복하기
sched.add_job(extract_links, 'interval', hours=1)
# 시작
sched.start()

위의 코드를 그대로 사용하실 분들은 웹사이트의 urlchat_idtoken 부분만 바꾸셔서 사용하시면 된다.

 

다만, 조조타운이 아닐경우, HTML의 구조가 달라서 확인이 안되실 겁니다. 

 

새로운 업데이트가 뜨는걸 알려주기 보다는 한시간마다 해당 상품의 재고를 확인하여 메세지로 보여준다.

 

모듈은 requests를 제외하고 3개 밖에 사용하지 않았다.

 

준비해야할 모듈

1. 웹 크롤링 용 모듈

(터미널에서 pip install bs4  해서 인스톨 하기)

2.텔레그램 메세지 용 모듈

(터미널에서 pip install python-telegram-bot 해서 인스톨 하기)

3.1시간 마다 반복하기 위한 스케쥴러 용 모듈

(터미널에서 pip install apscheduler 해서 인스톨 하기)

 

 

먼저 웹 크롤링 부분부터 살펴 보도록 하자.

# 1. 웹 크롤링 용 모듈
from bs4 import BeautifulSoup

def extract_links():
	# 재고확인을 하고 싶은 사이트의 주소
    url = 'https://paypaymall.yahoo.co.jp/store/zozo/item/51309849/?subcode_img=849/52309849/52309849b_18_d&img_type=z&subcode=GDID82867651'
    req = requests.get(url)
    html = req.text
    # 해당 url의 html문서를 soup 객체로 저장
    soup = BeautifulSoup(html, 'html.parser')
    search_result = soup.select('li.ItemStockFKU_item')

    stocks = []

    for i in search_result:
        color = i.select('span.ItemFKU_text')[0].text
        value = i.select('span.Icon')[0].attrs['class'][1]
        if(value=='Icon-radioOff'):
            stocks.append(color + ". 재고 있음")
        elif(value=='Icon-close'):
            stocks.append(color + ". 재고 없음")
        else:
        	stocks.append(color + ". site확인 요 : "+ url)

 

크롤링을 하기 위해서는 자신이 필요한 웹사이트를 준비해두고, 그 html문서를 soup 객체로 변환 시켜 주어야 한다.

 

BeautifulSoup의 API Documentation을 참고하자.

아래의 형식으로 html 문서를 soup 객체로 변환 시킬 수 있다.

(html이 아닌 xml의 경우 두번째 인자로 xml을 넣어주면 된다.)

soup = BeautifulSoup(markup, 'html.parser')

 

그 다음, 재고가 바뀔경우 바뀌는 값을 찾는다.

아래는 조조타운에 대한 예시이다.

 

이미지가 잘 안보이신다면 아래의 링크에서 직접 확인해 보셔도 된다.

 

조조타운아래의링크

 

왼쪽이미지는 재고가 있는경우, 오른쪽이미지는 재고가 없는 경우

사이트에 접속에 오른쪽 마우스 클릭하고 개발자 모드로 들어간다.

그리고 재고가 변경되는경우, 변경 되는 부분을 찾아본다.

 

위의 경우는, 빨간색으로 네모를 친곳이고 해당 값의 html의 태그와 class나 id를 확인한다.

#재고가 존재하는 경우, 아래 태그의 클래스 값이 "Icon Icon-radioOff"
<span class="Icon Icon-radioOff"></span>
#재고가 존재하지 않는 경우, 아래 태그의 클래스 값이 "Icon Icon-radioOff"
<span class="Icon Icon-close"></span>

위와 같이, 클래스의 값이 변화하는것을 확인할 수 있다(지금부터 이 값을 변화값이라 부르겠다).

 

그 이외의 html문서는 같기 때문에, 해당 변화값을 soup객체에서 찾으면 된다.

soup의 select 함수를 이용하면 쉽게 찾을 수 있다. 

 

조조타운 같은 경우는, 위의 크롬 개발자 모드에서 확인해 보면,

클래스의 이름이 ItemFKU_option 인 div 태그의 자식 태그변화값을 가지고 있다.

search_result = soup.select('div.ItemFKU_option')

#아래는 위의 search_result의 출력 값
[
  <div [hidden]="ItemImage_state.selectedIndex * 1 != 0" class="ItemFKU_option">
	  <div class="ItemFKU_item">
		  <span class="ItemFKU_head">カラー:</span>
		  <span class="ItemFKU_text">グレー</span>
	  </div>
	  <div class="ItemFKU_item"><span class="ItemFKU_head">在庫:</span>
		  <div class="ItemStockFKU">
			  <ul class="ItemStockFKU_list">
				  <li class="ItemStockFKU_item">
					  <span class="ItemStockFKU_name">FREE</span>
					  <span class="Icon Icon-radioOff"></span>
				  </li>
			  </ul>
		  </div>
	  </div>
  </div>
, 
  <div [hidden]="ItemImage_state.selectedIndex * 1 != 1" class="ItemFKU_option" hidden="">
	  <div class="ItemFKU_item">
	  	  <span class="ItemFKU_head">カラー:</span>
		  <span class="ItemFKU_text">ブラック</span>
	  </div>
	  <div class="ItemFKU_item">
      	  <span class="ItemFKU_head">在庫:</span>
		  <div class="ItemStockFKU">
			  <ul class="ItemStockFKU_list">
				  <li class="ItemStockFKU_item ItemStockFKU_item-disabled">
					  <span class="ItemStockFKU_name">FREE</span>
					  <span class="Icon Icon-close"></span>
				  </li>
			  </ul>
		  </div>
	  </div>
  </div>
, 
  <div [hidden]="ItemImage_state.selectedIndex * 1 != 2" class="ItemFKU_option" hidden="">
	  <div class="ItemFKU_item">
		  <span class="ItemFKU_head">カラー:</span>
		  <span class="ItemFKU_text">マルチ</span>
	  </div>
	  <div class="ItemFKU_item">
		  <span class="ItemFKU_head">在庫:</span>
		  <div class="ItemStockFKU">
			  <ul class="ItemStockFKU_list">
				  <li class="ItemStockFKU_item ItemStockFKU_item-disabled">
					  <span class="ItemStockFKU_name">FREE</span>
					  <span class="Icon Icon-close"></span>
				  </li>
			  </ul>
		  </div>
	  </div>
  </div>
]

 

상품의 3가지 색상에 따른 3가지의 재고 변화값을 가지고 있기 때문에, 배열값으로 search_result 변수에 들어가게 된다. 

 

그럼 해당 변화값을 찾기 위해 배열의 크기 만큼 반복문을 돌면서, 변화값(클래스의 값)을 받아옵니다.

#search_result 내부에서 변화값 찾기
for i in search_result:
	value = i.select('span.Icon')[0].attrs['class'][1]
    
#출력값(아래의 값이 3번 출력됨)
#재고가 있을경우,
Icon-radioOff
#재고가 없을경우,
Icon-close

 

해당 변화값을 받고, 조건을 넣어서 해당 색에 따른 상품의 재고가 있다는 말인지 없다는 말인지 알기 쉽게 처리하기 위해,

"Icon-radioOff"를 "재고 있음"으로 "Icon-close"를 "재고 없음"으로 변경해 주고 앞에 색의 값을 붙여준 값을 배열에 넣는다.

if(value=='Icon-radioOff'):
	stocks.append(color + ". 재고 있음")
elif(value=='Icon-close'):
	stocks.append(color + ". 재고 없음")
else:
	stocks.append(color + ". site확인 요 : "+ url)
    

 

마지막으로 stocks 라는 배열에 해당 값들이 잘 들어갔는지 확인 해 본다.

아래와 같이 stocks의 배열안에 있는 상품의 색과 재고 정보를 아래와 같이 출력이 된다면 웹 크롤링은 완료입니다.

 for stock in stocks:
        print(stock)
        
 #출력값 예시
グレー. 재고 있음
ブラック. 재고 없음
マルチ. 재고 없음

 

 

하나의 포스팅으로 끝을 내려 했지만, 생각보다 길어지는 바람에 모듈별로 포스팅을 나누기로 했습니다.

다음 포스팅은 <쇼핑몰 실시간재고 알림 봇 만들기 (2.텔레그램 Bot)> 으로 찾아뵙겠 습니다.

 

감사합니다.

반응형