ABOUT ME

-

Total
-
  • Python smtplib: 원하는 다나와 제품 가격 매일 알림 만들어보기
    컴퓨터/파이썬 2021. 1. 9. 17:53
    728x90
    반응형

    smtplib

     

    smtplib — SMTP 프로토콜 클라이언트 — Python 3.9.1 문서

    smtplib — SMTP 프로토콜 클라이언트 소스 코드

    docs.python.org

     

    결과물 미리 보기

    매일 내가 원하는 제품의 최저가로 표시된 가격을 구글 지메일로 보낼 것이다.

    내 gmail 함

     

    0. pip 설치

    HTML 스크랩을 편하게 하기 위해 beautifulsoup4를 설치한다.

    pip install beautifulsoup4

     

    1. 원하는 제품 최저가 표시 가격 불러오기

    원하는 다나와 제품의 링크를 복사한다. 예제는 아래 Razer Basilisk Ultimate

     

    [다나와] Razer Basilisk Ultimate

    최저가 230,000원

    prod.danawa.com

     

    requests를 통해 HTML를 불러와서 BeautifulSoup를 이용해서 element를 pick 한다.

    import requests
    
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 9.10; rv:69.0) Gecko/20100101 Firefox/68.0"
    }
    
    URL = "http://prod.danawa.com/info/?pcode=10129599&cate=112787"  # 다나와 링크
    
    
    def getPrice(url=URL) -> str:
        result = None
        try:
            result = requests.get(URL, headers=headers)
            result.raise_for_status()
        except requests.exceptions.HTTPError as http:
            print("HTTP Error:", http)
        except requests.exceptions.ConnectionError as conn:
            print("Connection Error:", conn)
        except requests.exceptions.Timeout as tm:
            print("Timeout Error:", tm)
        except requests.exceptions.RequestException as err:
            print("Something wrong:", err)
        assert result is not None
    
        soup = BeautifulSoup(result.content, "html.parser", from_encoding="iso-8859-1")
        price = soup.select_one("a.lwst_prc > em.prc_c")
        return price.text

     

    2. 메일 보내기

    메일을 맨 위 결과처럼 사진과 함께 예쁘게 보내기 위해서,

    다나와 제품을 캡처해서 py 파일이 있는 곳에 저장한다. (혹은 제품 사진까지 scrap)

    바이트 형식으로 읽어야 하며, 예제에선 basil.png이다. (800x590 크기로 지정됨)

     

    메일 형식은 아래와 같다.

    제목: [21/월/일] 오늘 "제품" 가격: 0원"

    내용: 사진 + 제품 이름과 제품 링크

     

    smtplib + 이미지 첨부해서 메일 보내기

    import smtplib
    from datetime import datetime
    from email.mime.image import MIMEImage
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    
    from pytz import timezone
    
    FROM = "자신@gmail.com"
    TO = "자신@gmail.com"
    PSWD = "FROM 메일의 비밀번호"
    
    def sendMail(mail=FROM, password=PSWD):
        server = smtplib.SMTP("smtp.gmail.com", 587)
        server.ehlo()
        server.starttls()
        server.ehlo()
        server.login(FROM, PSWD)
    
        prd = "Razer Basilisk Ultimate"
    
        now = datetime.now(timezone("Asia/Seoul"))
        nowPrice = f"오늘 {prd} 가격: {getPrice()}원"
        subject = now.strftime("[%y/%m/%d] ")
    
        msg = MIMEMultipart("related")
        msg["Subject"] = subject + nowPrice  # [21/01/09] 오늘 ~ 가격: ~원
        msg["From"] = FROM  # 발신
        msg["to"] = TO  # 수신
    
        # 이미지 크기는 알아서 설정 (width=가로, height=세로)
        html = f"""\
        <html>
        <head></head>
            <body>
            <img src="cid:image1" alt="Logo" style="width:800px;height:590px;"><br>
            <p><h1 style="text-align: center;font-size:20px;"><a href="{URL}" target="_blank" rel="noopener">{prd}</a></h1></p>           
            </body>
        </html>
        """
    
        imgSrc = MIMEText(html, "html")
        msg.attach(imgSrc)
    
        with open("basil.png", "rb") as img:
            msgImg = MIMEImage(img.read())
    
        msgImg.add_header("Content-ID", "<image1>")
        msg.attach(msgImg)
    
        server.sendmail(FROM, TO, msg.as_string())
        server.quit()

     

    3. 매일 실행하기

    더보기
    import smtplib
    import time
    from datetime import datetime
    from email.mime.image import MIMEImage
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    
    import requests
    from bs4 import BeautifulSoup
    from pytz import timezone
    
    
    FROM = "FROM@gmail.com"
    TO = "TO@gmail.com"
    PSWD = "PWD"
    
    URL = "http://prod.danawa.com/info/?pcode=10129599&cate=112787"
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 9.10; rv:69.0) Gecko/20100101 Firefox/68.0"
    }
    
    
    def getPrice(url=URL) -> str:
        result = None
        try:
            result = requests.get(URL, headers=headers)
            result.raise_for_status()
        except requests.exceptions.HTTPError as http:
            print("HTTP Error:", http)
        except requests.exceptions.ConnectionError as conn:
            print("Connection Error:", conn)
        except requests.exceptions.Timeout as tm:
            print("Timeout Error:", tm)
        except requests.exceptions.RequestException as err:
            print("Something wrong:", err)
        assert result is not None
    
        soup = BeautifulSoup(result.content, "html.parser", from_encoding="iso-8859-1")
        price = soup.select_one("a.lwst_prc > em.prc_c")
        return price.text
    
    
    def sendMail(mail=FROM, password=PSWD):
        server = smtplib.SMTP("smtp.gmail.com", 587)
        server.ehlo()
        server.starttls()
        server.ehlo()
        server.login(FROM, PSWD)
    
        prd = "Razer Basilisk Ultimate"
    
        now = datetime.now(timezone("Asia/Seoul"))
        nowPrice = f"오늘 {prd} 가격: {getPrice()}원"
        subject = now.strftime("[%y/%m/%d] ")
    
        msg = MIMEMultipart("related")
        msg["Subject"] = subject + nowPrice  # [21/01/09] 오늘 ~ 가격: ~원
        msg["From"] = FROM  # 발신
        msg["to"] = TO  # 수신
    
        html = f"""\
        <html>
        <head></head>
            <body>
            <img src="cid:image1" alt="Logo" style="width:800px;height:590px;"><br>
            <p><h1 style="text-align: center;font-size:20px;"><a href="{URL}" target="_blank" rel="noopener">{prd}</a></h1></p>           
            </body>
        </html>
        """
    
        imgSrc = MIMEText(html, "html")
        msg.attach(imgSrc)
    
        with open("basil.png", "rb") as img:
            msgImg = MIMEImage(img.read())
    
        msgImg.add_header("Content-ID", "<image1>")
        msg.attach(msgImg)
    
        server.sendmail(FROM, TO, msg.as_string())
        server.quit()
    
    
    if __name__ == "__main__":
        while True:
            sendMail()
            time.sleep(60 * 60 * 24)
    
    

    AWS EC2를 이용하거나 매일 컴퓨터 켜놓거나, cronjob을 이용해서 컴퓨터 켤 때마다 보내게 하면 된다.

    AWS EC2를 이용하게 되면 그냥 아래 명령어로 실행해놓고 끄면 된다.

     

    Python: 무료 Cloud Flask 서버 만들기 (AWS EC2 + S3)

    AWS 클라우드 서비스 | 클라우드 컴퓨팅 솔루션| Amazon Web Services 브라우저 기반 셸, 더 안전하고 손쉬운 카오스 엔지니어링, 기존 도구와 서비스의 향상된 기능 발표 내용 살펴보기 aws.amazon.com 1.

    choiseokwon.tistory.com

     

    백그라운드에서 계속 실행

    if __name__ == "__main__":
        while True:
            sendMail()
            time.sleep(60 * 60 * 24)
    

    terminal

    nohup python danawa.py &

     

    오류 상황

    만약 Username and password not accepted 에러가 뜨면, 발신(FROM) 메일의 보안 수준을 낮춰야 한다.

    아래 들어가서 사용함으로 변경

     

    구글 계정 보안 설정

    하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

    accounts.google.com

     

    728x90

    댓글