재입고 알림 봇 만들기-2 프로그램 개발(스크래핑)

이전 편 에서는 무엇을 하고자 하는지, 어떤 것을 준비하면 되는지 알아봤습니다. 이번에는 준비된 환경에서 실행될 프로그램을 만들어 보겠습니다. 기본 프로그램은 처음 글(재입고 알림 봇 만들기)과 큰 차이가 없습니다. 다만 설명을 상세히 하고 스크래핑 사례를 추가했습니다.

프로그램은 크게 3개로 구분됩니다.

  • 스크래핑 : 특정 인터넷 주소의 페이지를 읽어오고 품절 여부를 체크합니다.
  • 메신저 : 알림을 보냅니다.
  • 메인 프로그램 : 스크래핑 결과를 확인하고 메신저 프로그램으로 알림을 보내도록 합니다.

스크래핑

사례-11번가

  1. 11번가 아무 상품이나 들어가서 브라우저의 개발자 모드를 켭니다. 보통 F12 키를 누르면 개발자 모드로 들어가집니다. 개발자 모드에서는 HTML 태그를 보고 자바스크립트를 디버그하거나 CSS를 수정하는 등 다양한 것들을 할 수 있습니다.
  2. 개발자 도구의 요소(Elements) 탭에서 선택기를 켭니다. 크롭에서는 단축키는 Ctrl + Shift + C 라고 나오네요. 익스플러로나 다른 브라우저에서는 키가 다를 수 있습니다. 아이콘은 대부분 비슷하게 생겼는데 네모 상자에 마우스 포인트가 들어있습니다.

  3. 요소 선택기가 켜진 상태에서 아이템 화면으로 전환해 구매하기 버튼을 찾아 누릅니다. 요소 탭에 해당하는 태그를 찾아서 보여줍니다. 대략 구조를 보자면 div 태그 안에 a 태그가 있고 그 안에 em 태그로 강조 표시된 구매하기 텍스트가 들어있습니다. 이 중 a 태그의 class 속성을 통해 구매 가능한 상태인지 체크할 수 있을 것 같습니다. a 태그 중 class가 btn_dshop buying position_top 인 요소가 있으면 구매 가능한 상태로 판단할 수 있을 것입니다.

  4. Jupyter Notebook에서 간단하게 테스트를 해봤습니다.

  5. 최종적으로 체크 함수는 이렇게 됩니다.

코드를 살펴보자면

  • 3라인 : a 태그 중 구매하기 버튼의 클래스를 찾습니다. 11번가의 경우 class=”btn_dshop buying position_top” 으로 구매하기 버튼을 식별할 수 있습니다.
  • 5라인 : 만약에 3라인에서 찾아진 결과가 없으면(=구매하기 버튼이 없으면) 재고가 없는 것으로 판단하고 False를 리턴합니다.
  • 6라인 : 5라인의 조건문이 통과한 경우(3라인에서 찾아진 결과가 있으면) 재고가 있는 것으로 판단하고 True를 리턴합니다.

사례-쿠팡

전반적인 절차는 11번가와 동일합니다.

  1. 아이템을 하나 선택하고 들어가서 브라우저의 개발자 모드를 켜고 요소 선택기로 품절 버튼을 선택해 태그를 확인합니다.
  2. 간단한 코드로 스크래핑이 동작하는지 확인해 봅니다.

  • headers 부분을 넣지 않고 요청을 보냈을 때 응답이 오지 않았습니다. header의 User-Agent라는 것은 어떤 브라우저인지를 식별하기 위해 사용됩니다. 이 부분이 없을 때 서버에서 응답이 오지 않는 경우가 종종 있습니다. 내가 사용하는 브라우저(정상적으로 응답이 오는)의 User-Agent 부분을 확인하려면 개발자 도구에서 네트워크 부분에 들어간 뒤 왼쪽 탭에서 아무거나 선택해봅니다. 오른쪽 해더 부분에서 Request Header의 user-agent를 찾아보면 됩니다.
  • 사이트에서 스크래핑을 차단하기 위해 이런저런 필터링을 하기도 합니다. 대부분 실제 브라우저에서 나가는 요청을 최대한 비슷하게 만들어주면 넘어갈 수 있습니다.
  1. 최종적으로 체크 함수는 이렇게 됩니다.

마지막으로 전체 프로그램을 다시 살펴보겠습니다.

  • StockCheck 라는 클래스가 스크래핑 부분을 담당하게 만들었습니다.
  • 8, 65 라인 : checkMethod는 품절인지 여부를 체크하는 함수입니다. 사이트별로 체크하는 방법이 다르므로 StockCheck에 동적으로 들어갈 수 있게 했습니다.
  • 10 라인 : 최종 상태를 저장하기 위한 변수입니다. 최종 상태와 새로 스크래핑한 상태가 바뀌었을 때 메신저로 알림을 보내기 위해 필요한 부분입니다.
  • 13 라인 : getResponse 함수는 HTTP 요청을 담당합니다. 이 부분은 header를 추가할 수 있게 좀 바꿀 필요가 있어 보이네요.
  • 21 라인 : 가장 중요한 함수입니다. 응답을 가져오고(getReponse 실행) 체크 함수를 실행해 결과를 리턴합니다. encoding 부분은 종종 BeautifulSoup에서 인코딩 관련 문제가 생길 때 인코딩을 강제 설정할 수 있도록 하기 위해 필요합니다.
  • 29 라인 : check 함수를 실행하고 상태가 바뀌었는지 체크하는 함수입니다.
  • 39 라인 : str은 클래스의 기본 함수를 오버라이딩 한 부분입니다. 로그 등을 출력할 때 보기 쉽게 만들기 위해 썼습니다.
  • 43 라인 : 이 아래는 테스트 코드 입니다. 파이썬에서 간단한 테스트를 하기 위해 흔히 사용하는 방법입니다. 다른 클래스에서 이 클래스를 가져와서(import) 쓸 때는 이 부분이 실행되지 않습니다. 이 프로그램(파일)을 직접 실행할 때만 이 부분이 실행됩니다.
  • 44 라인 : 재고 체크 함수 샘플입니다. 레고샵 용입니다.
  • 63 ~ 69 라인 : StockCheck 객체를 만들고 체크를 실행하는 테스트 코드입니다. 메인 프로그램 쪽에서는 이런 식으로 사용하게 됩니다.

글이 길어져서 메신저와 메인 프로그램 부분은 다음으로 나누었습니다.

재입고 알림 봇 만들기-2 프로그램 개발(스크래핑)”의 24개의 생각

  1. Doy 답글

    봇 만들기 1을 보고 2를 보게 되었습니다.
    만들기1에서 나온 질문에 이렇게 2까지 작성하시는 작성자님의 favor에 감탄하게 됩니다.

    파이썬에 파 자도 모르지만,, 그리고 아직 따라해보지는 않았지만
    쉽게 따라할 수 있게 안내해주시는 포스팅인것 같습니다.

    웹프로그래밍과는 전혀 상관이 없는 직군이지만,
    꼭 재고알림만 아니더라도 발을 한 번 들여보고 싶은 마음이 드네요 ㅎㅎ

    감사합니다~

  2. JH 답글

    안녕하세요~ 블로그 보고 따라하고 있는데 질문이 있어 댓글을 남깁니다.
    위의 예제에서 11번가의 경우 class의 이름으로 재고를 판단하였는데 class = ~~ 가 아닌 class_ = 인 이유는 무엇인가요?

    • JH 답글

      그리고 실례가 안된다면 혹시 따라한 코드를 한번 봐주실 수 있으신가요..?
      sold out인데도 가끔씩 True가 떠서 알람이 오네요.

      • samsee 글쓴이답글

        class가 파이썬 예약어라서 class_ 로 쓰는걸로 알고 있어요. 코드 올려주세요~

      • samsee 글쓴이답글

        쇼핑몰이 스크래핑을 막을 수 있게 보안이 강화된 걸로 보이네요. Cookie와 User-Agent를 헤더에 넣어줘야 해요. 두 가지 데이터 모두 브라우저 개발자 도구를 이용해서 알아낼 수 있습니다.
        개발자도구 – 네트워크에서 Header 보시면 Request Header라고 있는데 거기에 위의 두 가지 값을 가져와서 getResponse 함수 부분에 넣어줘야 합니다. 넣는 방법은
        https://dgkim5360.tistory.com/entry/python-requests
        이 블로그 포스트 확인해보세요.

        • JH 답글

          감사합니다 선생님
          덕분에 좋은 공부가 되었습니다 ^^ 추가해주니까 잘 되는거 같아요

          • samsee 글쓴이

            도움이 되셨다니 기쁘네요.

  3. MC 답글

    안녕하세요~ 스크래핑 관련 하여 너무 헷갈려서 문의 드리려고 합니다.

    아무것도 모르는 상태에서 따라하기가 너무 버겁네요.

    https://kr.louisvuitton.com/kor-kr/products/neonoe-mm-monogram-nvprod290007v#M44887

    여기 재고 확인을 하려고 합니다.

    현재 이렇게 만들어 보았습니다.
    https://blog.naver.com/kwmich/221946864253

    텔레그램 알람까지는 성공했는데 오류가 너무 많이 나는거 같아요.

    도움 부탁드려도되겠습니까??

    • samsee 글쓴이답글

      안녕하세요. 대략 이런 코드로 스크래핑 하시면 될것 같습니다.

      import requests

      lv_url = “https://kr.louisvuitton.com/kor-kr/products/neonoe-mm-monogram-nvprod290007v#M44887”

      res_lv = requests.get(lv_url, headers={‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36’})
      from bs4 import BeautifulSoup

      soup_lv = BeautifulSoup(res_lv.text, “html.parser”)
      len(soup_lv.findAll(“div”, {“id”: “notInStock”})) # 1 이면 품절, 0 이면 재고 있음으로 판단.

      잘 안되는 부분 있으면 알려주세요~

  4. 제인유 답글

    코드 올려주신 덕분에 조금 수정해서 잘 쓰고 있습니다. 마스크 재고 알림용으로 쓰는데 잘 동작해요. 근데 알림이 와서 가보면 그새 다른 사람들이 1-2분동안 다 구입해가는 바람에 알림이 와도 살 수가 없는 웃픈 상황입니다. ㅎㅎ
    Class StockCheck의 statusChanged()함수가 4개의 변수를 return하는데 아래 코드에서는 3개의 변수로 받아서 그런지 에러가 나서 statusChanged()함수가 그냥 3개 변수만 return하는 걸로 수정해봤습니다.
    (status_changed, last_status, current_status) = lego_friends_perk.statusChanged()

    • samsee 글쓴이답글

      그렇네요! 실수가 있었습니다. 말씀하신대로 3개 변수만 리턴하는게 맞을 것 같습니다.
      마스크 대란 아직 안 끝났나요 ㅠ 저도 찾는 물건 몇 개 있어서 돌리고 있는데 아예 재고가 뜨지도 않네요 ㅎ

  5. VAN 답글

    올려주신 글 덕에 많은 도움이 되고 있습니다.
    기능을 확장하고자 몇 군데 더 테스트 중인데 안되는 쇼핑몰들이 있어서 혹시 도움을 받을 수 있을까 싶어서 염치없지만 이렇게 글을 남겨봅니다.
    혹시 쇼핑몰 중에 [ C 제이 몰 ]같은 경우는 좀 더 고려해야 할 사항이 있을까요?
    좀 자세히 말씀드리자면 특정 class를 가진 특정태그를 불러오지를 못하고 있습니다.
    일정 깊이를 넘어가면 못찾는걸로 봐서 막연히 트리구조가 원인이 아닐까라고 생각만 하는데 기초지식이 없어서인지 해결이 쉽지가 않습니다.
    번거로우시겠지만 조언 부탁드립니다.

  6. 질문 답글

    개발이라는 걸 전혀 모르는 사람인데 필요한 물품이 갖고 싶어서 검색해서 들어왔습니다.
    파이썬이라는 걸 설치하고 윗 코드를 전부 복사해서 붙여넣었고, requests라는 것도 설치하였는데
    45번째 줄의 from bs4 import BeautifulSoup 부분에서 에러가 나옵니다.
    bs4라는 것은 무엇인가요? 그리고 함수 부분과 전체 프로그램 코드를 따로따로 작성해야 할까요?

    • samsee 글쓴이답글

      bs4 는 HTML을 해석하기 위한 라이브러리 입니다.
      requests 처럼 설치를 하시면 됩니다. `pip install beautifulsoup4` 해보세요.
      지금 보니 라이브러리 설치하는 부분을 빼먹었네요..

  7. 김강연 답글

    먼저, 좋은 프로그램 개발 감사드립니다.
    질문이 하나 있습니다. StockCheck 클래스의 함수 statusChanged가 리턴하는 값들은 총 4개인데, 68라인에서 그 리턴값들을 저장하는 변수는 3개 밖에 안되는 것으로 보입니다. 실행 시에 ValueError가 뜨기도 하고요. 제가 파이썬이 주 언어가 아니다보니 잘 모르겠습니다.. 설명해주시면 감사하겠습니다

    • samsee 글쓴이답글

      제가 다른 프로그램 수정하다가 StockCheck에 있던 샘플 코드를 수정 안 했네요..
      리턴 값을 무시하는 방법을 사용해 보세요. `(a, b, c, *waste) = class.statusChanged()`
      이렇게 하시면 리턴되는 4개 중에 3개의 값만 a, b, c에 담고 나머지는 waste에 들어가게 됩니다.
      StockCheck 에 있는 클래스 바깥의 스크립트 부분은 단위 테스트? 용도 입니다. 나중에 main 클래스에서 수정하다가 클래스 메서드만 바꿔서 에러나는 거였습니다 ^^

  8. 김강연 답글

    답변 감사드립니다. 남은 리턴값을 무시하는 방법이 있었군요. 흥미롭네요. 더 배워갑니다 🙂

  9. K 답글

    안녕하세요
    특정사이트 재입고 모니터링 개발 의뢰도 받으시나요.

    • samsee 글쓴이답글

      안녕하세요~ 답이 많이 늦었네요. 스크래핑 개발에 문제가 없는 곳이라면 도와드릴 수 있습니다. 텔레그램 tldrsam 으로 연락 주세요.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다