Github Actions으로 로또 자동 구매하기 (지속적 로또)

![buy_lotto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144058/6d207ac1-ba07-9c95-965d-0c9c25537247.png)

## TL;DR
> [인터넷 로또 구매](https://dhlottery.co.kr/)가 가능하더라고요. 
> 매주 토요일 아침 08:55에 로또 1천원 자동 구매를 걸어둡니다.

## 준비물
- 예치금 사전 충전 https://dhlottery.co.kr/payment.do?method=payment

## 구축하기
### GitHub Private 저장소 생성
:lock: Private 로 생성해주세요. 
예) 저장소 이름 : lotto-action
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144058/f45d74b7-8595-3a86-bba1-db843278a253.png)

### 소스코드 작성
2개의 파일이 필요합니다. 
`action.yml`
`buy_lotto.py`

:white_check_mark: `.github/workflows/` 하위 경로에 `action.yml` 있어야만 **GitHub Actions** 이 동작합니다!

```bash
$ root@master:github-action# tree -al -I '.git'
.
├── .github
│   └── workflows
│       └── action.yml
├── README.md
└── buy_lotto.py
```
```yml:action.yml
name: Lotto Buy Bot (로또 구매봇)

#on: [push]
on:
  schedule:
    - cron: '55 23 * * 5' # UST 기준의 크론. UST 23:55 는 KST 08:55

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.7]

    steps:
    - uses: actions/checkout@v2
    - name: Set up python ${{ matrix.python-version }}
      uses: actions/setup-python@v1
      with:
        python-version: ${{ matrix.python-version }}
    
    - name: Install python package
      run: |        
        pip install selenium
        pip install requests        
        pip install twython
        pip install pillow    
        pip install gspread        
        pip install --upgrade google-api-python-client oauth2client
        pip install playwright
        python -m playwright install ${{ matrix.browser-channel }} --with-deps
    
    - name: Install ubuntu package
      run: |        
        sudo apt-get install fonts-unfonts-core
        sudo apt-get install fonts-unfonts-extra
        wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add        
        sudo apt-get install google-chrome-stable    
        wget https://chromedriver.storage.googleapis.com/100.0.4896.20/chromedriver_linux64.zip
        unzip ./chromedriver_linux64.zip           
      
    - name: Run!      
      run: |        
        python ./buy_lotto.py   

```

수정1과 수정2를 본인의 동행복권 아이디와 패스워드로 변경해주세요.

```python:buy-lotto.py
from playwright.sync_api import Playwright, sync_playwright
import time

# 동행복권 아이디와 패스워드를 설정
USER_ID = '<아이디>' # 수정1
USER_PW = '<비밀번호>' #수정2

# 구매 개수를 설정
COUNT = 1

def run(playwright: Playwright) -> None:

    # chrome 브라우저를 실행
    browser = playwright.chromium.launch(headless=True)
    context = browser.new_context()

    # Open new page
    page = context.new_page()

    # Go to https://dhlottery.co.kr/user.do?method=login
    page.goto("https://dhlottery.co.kr/user.do?method=login")

    # Click [placeholder="아이디"]
    page.click("[placeholder=\"아이디\"]")

    # Fill [placeholder="아이디"]
    page.fill("[placeholder=\"아이디\"]", USER_ID)

    # Press Tab
    page.press("[placeholder=\"아이디\"]", "Tab")

    # Fill [placeholder="비밀번호"]
    page.fill("[placeholder=\"비밀번호\"]", USER_PW)

    # Press Tab
    page.press("[placeholder=\"비밀번호\"]", "Tab")

    # Press Enter
    # with page.expect_navigation(url="https://ol.dhlottery.co.kr/olotto/game/game645.do"):
    with page.expect_navigation():
        page.press("form[name=\"jform\"] >> text=로그인", "Enter")
    
    time.sleep(5)
    
    page.goto(url="https://ol.dhlottery.co.kr/olotto/game/game645.do")    
    # "비정상적인 방법으로 접속하였습니다. 정상적인 PC 환경에서 접속하여 주시기 바랍니다." 우회하기
    page.locator("#popupLayerAlert").get_by_role("button", name="확인").click()
    print(page.content())

    # Click text=자동번호발급
    page.click("text=자동번호발급")
    #page.click('#num2 >> text=자동번호발급')

    # 구매할 개수를 선택
    # Select 1
    page.select_option("select", str(COUNT))

    # Click text=확인
    page.click("text=확인")

    # Click input:has-text("구매하기")
    page.click("input:has-text(\"구매하기\")")

    time.sleep(2)
    # Click text=확인 취소 >> input[type="button"]
    page.click("text=확인 취소 >> input[type=\"button\"]")

    # Click input[name="closeLayer"]
    page.click("input[name=\"closeLayer\"]")
    # assert page.url == "https://el.dhlottery.co.kr/game/TotalGame.jsp?LottoId=LO40"

    # ---------------------
    context.close()
    browser.close()

with sync_playwright() as playwright:
    run(playwright)
```

## 동작 확인하기
lotto-action 저장소에 위에 작성한 `action.yml`와 `buy_lotto.py` 2개의 파일을 업로드 합니다.
토요일 오전 08:55 분에 동작합니다. (약 2분 소요)
Actions 탭에서 실행 결과를, 로또 마이페이지에서 구매 결과를 확인할 수 있습니다.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144058/68b8311e-6bb0-187f-1ea8-b3f86eec87ef.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144058/c7d6a48f-31df-4ff2-8b95-956bf54d09a5.png)
<iframe width="560" height="500" src="https://www.youtube.com/embed/p2F9JuO0_0o" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## 참고
- https://www.clien.net/service/board/lecture/16835687
- `Github Actions` + `Playwright` 를 사용하였습니다.