이상한 MYPI

이상한
접속 : 6949   Lv. 113

Category

Profile

Counter

  • 오늘 : 604 명
  • 전체 : 8362942 명
  • Mypi Ver. 0.3.1 β
[공부 - PG] 가격 변동 확인용 프로그램 제작 (1) 2021/05/16 AM 01:52
뭐... 내용은 그냥 페이지 열어서 상품 가격만 파싱해서

DB 저장해 두는 일련의 작업입니다.

며칠전에 구공기 세일 한거 모르고 넘어가서 만들어 봤습니다만...

같은 기능 하는 사이트 있기 때문에 그냥 헛짓;;

DB는 안쓰면 이전 가격 확인이 안되지만 큰 데이터 쓰는게 아니니 MYSQL도 오버다보니 SQLITE를 씁니다



대충 하루 걸려서 그냥 혼자 쓸 정도는 될듯 하네요

 
소스 문제점
1. 예외처리 1도 안함
1. 통보를 메일로 하는데 SMTP 암호를 하드코딩하는 강렬함
1. 페이지 소스내에 XPATH 소스에 박아서 처리하기 때문에 초기 범용성을 사라졌음
1. DB 기본 입력 페이지 같은거 없음.. 브라우져 깔아서 넣어야 됨

그러니 수정할 사람은 알아서;;;

통보 메일 아니라 채팅봇 올려서 라인이나 스카이프로 할려고 했지만 역시 귀찮으니 스킵
 

환경 : 라즈베리파이(라즈비안 써서 CronJob으로 매시간 돌리지만 소스는 OS안가림 셀레니움 드라이버 패스 제외)

 

언어 : 파이썬3

 

라이브러리 : Selenium(Chrome)

 

DB : sqlite3


 

 DB구성

과거 가격을 기록할 테이블

img/21/05/16/17970d28b67224d0.png

 

 본격적으로 체크할 상품 정보를 적을 테이블

ITEM_ID ID로 자동상승(AI)를 킨건 좀 오버긴 한데 없으면 그것되로 불편

SITE_TYEP SITE테이블과 연동할 필드

NAME 상품 이름 메일 출력용으로 씀

OPTION1,2,3 URL의 KEY가 될 값, 3은 안쓰지만 일단 넣어둠

DEL 0이 아니면 더 이상 트레킹 안할 려고 추가

img/21/05/16/17970d28d07224d0.png

 

 ITEM 테이블과 연동해서 URL 작성용으로 만든 테이블

SITE_TYPE ITEM과 연동용으로 ID용으로 씀

URL 사이트 URL {0}~{2}까지 지원해서 URL 생성용

URL_TYPE MS사이트가 KEY가 2개라서 급하게 추가

SITE_MEMO 진짜 메모용... 실 소스에 전혀 안씀

img/21/05/16/17970d28e5c224d0.png

 

 ITEM 테이블 실제로 들어간 값

img/21/05/16/17970d290d6224d0.png

 

 SITE테이블 실제 값

img/21/05/16/17970d29322224d0.png

 

 파이썬 소스

제 개인 정보 나올 수 있는것만 지우고 올립니다


 from selenium import webdriver
from selenium.webdriver.chrome.options import Options

import smtplib, ssl
import email.utils
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

import sqlite3

#import logging
#logging.basicConfig(level=logging.DEBUG, filename="test.log", format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')

options = Options()
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
chrome_prefs = {}
options.experimental_options["prefs"] = chrome_prefs
chrome_prefs["profile.default_content_settings"] = {"images": 2}
chrome_prefs["profile.managed_default_content_settings"] = {"images": 2}
driver = webdriver.Chrome(executable_path="/usr/lib/chromium-browser/chromedriver", chrome_options=options)

dbPath = "./"
dbFileName = "PriceChk.sqlite3"
conn = sqlite3.connect(dbPath + dbFileName)

cur = conn.cursor()

dataList = cur.execute("select B.ITEM_ID, B.NAME, A.SITE_TYPE, A.URL, A.URL_TYPE, B.OPTION1, B.OPTION2, B.OPTION3 from SITE A, ITEM B where B.DEL=0 AND A.SITE_TYPE=B.SITE_TYPE").fetchall()
for data in dataList:
    url = ""
    if data[4] == 1:
        url = data[3].format(data[5])
    elif data[4] == 2:
        url = data[3].format(data[5], data[6])
    elif data[4] == 3:
        url = data[3].format(data[5], data[6], data[7])

    #print(url)
    driver.get(url)
    
    newPrice = ""
    if data[2].startswith("MS"):
        if data[2] == "MSM2":
            buyText = "Buy "
            for btn in driver.find_elements_by_xpath("//button[@data-focus-rank='600']"):
                tempValue = btn.get_attribute("aria-label")
                if tempValue.startswith(buyText):
                    newPrice = tempValue[len(buyText):]
                    break
        else:
            priceValue = driver.find_element_by_xpath("//meta[@itemprop='price']")
            newPrice = priceValue.get_attribute("content")
    elif data[2].startswith("AM"):
        priceValue = driver.find_element_by_xpath("//-nput[@name='displayedPrice']")
        newPrice = priceValue.get_attribute("value")
   
    oldPriceSelect = cur.execute("select ITEM_ID, PRICE, DATE from DATA where ITEM_ID = ? order by DATE desc limit 1", (str(data[0]),)).fetchone()
    oldPrice = ""
    if not oldPriceSelect is None:
        oldPrice = oldPriceSelect[1]

    if oldPrice != newPrice:
        cur.execute("insert into DATA ( ITEM_ID, PRICE, DATE ) VALUES (?, ?, datetime('now', 'localtime'))", (data[0], newPrice))
        fromaddr = <<보내는 메일 주소>>
        toaddr = <<받는 메일 주소>>
        
        msgBody = "{0}의 가격 변경\n{1}→{2}\n{3}".format(data[1], oldPrice, newPrice, url)
        msg = MIMEMultipart()
        msg['From'] = email.utils.formataddr(('가격봇', fromaddr))
        msg['To'] = email.utils.formataddr(('너님', toaddr))
        msg['Subject'] = "{0}의 가격 변경".format(data[1])
        msg.attach(MIMEText(msgBody))

        id = fromaddr
        password = <<메일 계정 패스워드>>

        context = ssl.create_default_context()
        with smtplib.SMTP(<<매일SMTP서버>>, <<포트번호>>) as server:
            server.ehlo()  # Can be omitted
            server.starttls(context=context)
            server.ehlo()  # Can be omitted
            server.login(id, password)
            server.sendmail(fromaddr, toaddr, msg.as_string())

conn.commit()
conn.close()
driver.close()
driver.quit()


사용하는 메일서버 SSL에 문제가 있어서 ehlo는 오버플로우에서 찾아서 처리했습니다;;;
 
보통 SMTP서버는 문제 없을 겁니다. 특히 포털 SMTP쓸 경우에는.
 
응용할 때는 알아서 줄여서;;;;

그리고 셀레니움 옵션은 그냥 옛날에 만든거 그냥 갖다 붙인거라 거의 의미 없습니다.. 응용시 참고하세요..



몇명이나 참고 하겠냐 만은;;; 다른 사람보다 제가 보관용으로 올리는 소스여서;





추기
VS CODE 복붙하니 소스에 색이 자동으로 붙어서 그냥 뒀는데..

결과는 소스 개판이 되네요...

이쪽 공유용으로 만든 사이트가 아니라 영 불편하네요..

신고

 

좋은사람임    친구신청

와우...
X