일본 학생 지원기구 장학금의 상환 상황 취득

1. 배경



대학 시대에 일본 학생 지원기구의 장학금을 빌리고,
매월 반환합니다.
앞으로 긴 교제 ()가되기 때문에,
반환 금액의 잔액을 매번 스칼라넷에 로그인하여 확인합니다.
그래서 우리는 원하는 정보 만 스크래핑하여 얻은 다음 세부 정보 페이지를 스크쇼하는 스크립트를 작성했습니다.
코드의 전모는 이쪽( gist )
PhantomJS 개발이 끝나면 Google Chrome을 사용하도록 다시 작성되었습니다 (20200403).

대여 총액, 월부 반환 금액, 월부 반환 잔액 (원금)을 지정하고 있지만 CSS 선택기의 곳을 괴롭히면 다른 정보에도 대응할 수 있습니다.

2. 환경


  • Python 3.6.3
  • PhantomJS 2.1.1

  • 파이썬 패키지는 다음과 같습니다.
  • beautifulsoup4==4.6.0
  • selenium==3.7.0
  • lxml==4.1.1

  • 3. 동작



    스크립트를 실행하면 다음과 유사한 메시지가 콘솔에 출력됩니다.
    $ python3 main.py
    ログイン中...
    ログイン完了しました.
    今回の更新日: 11月10日
    次回の更新日: 12月12日
    学校名: XX大学
    貸与総額: 1,800,000円
    月賦返還額: 12,214円
    月賦返還残額(元金): 1,401,469円
    

    출력 내용은 contents_[日付].json라는 JSON 형식 파일로 저장됩니다.

    또한 다음과 같은 png 형식의 스쿠 쇼 이미지가 大学名.png라는 이름으로 로컬에 저장되어 있는지 확인할 수 있습니다.


    4. 코드



    Selenium으로 로그인, 스쿠쇼, 퍼스 모두를 끝낼 수도 있습니다만,
    떡은 떡집이기 때문에 퍼스 부분은 BeautifulSoup을 이용합니다.
    from bs4 import BeautifulSoup
    from selenium import webdriver as wd
    from selenium.webdriver.support.ui import Select
    

    흐름으로,
    1. Selenium+PhantomJS에서 로그인 -> HTML 소스 얻기 -> 스쿠쇼
    2. 취득한 HTML 소스를 BeautifulSoup로 퍼스

    됩니다.

    스칼라넷 로그인 양식,
    미리 확인한 id 속성 등을 바탕으로 입력합니다.
    id, pass, num은 자신의 것으로 다시 작성하십시오.
    장학생 번호는 XXX-YY-ZZZZZ입니다.
    url = "https://scholar-ps.sas.jasso.go.jp/mypage/login_open.do"
    driver = wd.PhantomJS()
    driver.implicitly_wait(30)
    driver.get(url)
    
    try:
        # ID,Passwordの入力
        driver.find_element_by_id("login_open_userId").send_keys(id)
        driver.find_element_by_id("login_open_password").send_keys(pass)
        driver.find_element_by_id("login_open_login_submit").click()
        # 奨学生番号の入力
        driver.find_element_by_id("syogkseiBgKakunin_open_syogkseiBg1").send_keys("XXX")
        select = Select(driver.find_element_by_id("syogkseiBgKakunin_open_syogkseiBg2"))
        select.select_by_visible_text("YY")
        driver.find_element_by_id("syogkseiBgKakunin_open_syogkseiBg3").send_keys("ZZZZZ")
        driver.find_element_by_id("syogkseiBgKakunin_submit_button").click()
        print("ログイン完了しました.")
    except:
        print("ログインに失敗しました.")
        sys.exit()
    

    implicitly_wait에서 목표 요소를 즉시 찾을 수 없더라도 최대 30 초를 기다리는 설정을합니다.

    이번에 원하는 것은 톱 페이지와 상세 페이지의 HTML 소스이므로 각각 html_top, html_univ라는 이름으로 가져옵니다.
    또한 웹 드라이버가 살아있는 동안 세부 페이지의 스크린 샷을 동시에 찍습니다.
    # トップページの取得
    html_top = driver.page_source
    
    # 詳細ページの取得
    num = "%s%s%s" % (str(profile["num1"]), str(profile["num2"]), str(profile["num3"]))
    element = driver.find_element_by_xpath("//input[@value=%s]" % num)
    element.click()
    html_univ = driver.page_source
    
    css = "#main > div > div > div.content-syosaiJoho > div > div.content-l-syosaiJoho > "
    css += "div.content-l-main-syosaiJoho > table > tbody > tr > td.syosaiJoho-area > div:nth-of-type(1) > "
    css += "div.content-m-main-syosaiJoho > table > tbody > "
    
    # スクリーンショット
    name = driver.find_element_by_css_selector(self.css + "tr:nth-of-type(3) > td.content-td-syosaiJoho").text
    driver.save_screenshot("%s.png" % name)
    
    driver.close()
    

    여기서 png 파일의 이름을 大学名.png로 만들기 위해 css 선택기를 사용하여 요소를 식별합니다.
    지금까지는 XPath로 요소를 지정해 왔지만, 이후 사용하는 BeautifulSoup는 XPath에 대응하지 않습니다. 그 관계로 CSS 선택기를 플라잉 적으로 여기에서 준비하고 있습니다.
    webdriver를 사용하면 driver.close()로 지 웁니다.

    그런 다음 방금 얻은 HTML 소스에서,
    갱신일 정보, 대여 총액, 월부 반환 금액, 월부 반환 잔액을 추출합니다.soup.select_one로 CSS 선택기를 인수에 제공하면 쉽게 얻을 수 있습니다. BeautifulSoup 편리!
    CSS 선택기의 위치를 ​​적절한 정보 선택기로 바꿉니다.
    # 更新日の取得
    soup = BeautifulSoup(html_top, 'lxml')
    css_information = "#main > div > div > div.content-zentaiGaiyo > div > div.content-l-infomation > div.content-l-main-infomation > div"
    information = soup.select(css_information)
    for i in information:
        if i.prettify().count("次回の更新予定日は"):
            update_info = i.prettify().split("次回の更新予定日は")[1] # この辺スマートじゃない
    pattern = re.compile("\d+"+u"月"+"\d+"+u"日")
    dates = pattern.findall(update_info)
    next_date = dates[0]
    updated_date = dates[1]
    

    갱신 정보 빼내는 곳은, 정규 표현을 잘 사용하면 스마트하게 될 것...
    정규식 강자, 조언 해주십시오.
    # 返済状況の取得
    get_contents(self, html_univ, type):
    soup = BeautifulSoup(html_univ, 'lxml')
    name  = soup.select_one(self.css + "tr:nth-of-type(3) > td.content-td-syosaiJoho").get_text()
    total = soup.select_one(self.css + "tr:nth-of-type(6) > td.content-td-syosaiJoho").get_text()
    pay   = soup.select_one(self.css + "tr:nth-of-type(9) > td.content-td-syosaiJoho").get_text()
    balance = soup.select_one(self.css + "tr:nth-of-type(12) > td.content-td-syosaiJoho").get_text()
    
    # 空白と改行の除去
    name  = re.sub('[\n ]', '', name)
    total = re.sub('[\n ]', '', total)
    pay   = re.sub('[\n ]', '', pay)
    balance  = re.sub('[\n ]', '', balance)
    contents = {"学校名":name,"貸与総額":total,"月賦返還額":pay,"月賦返還残額(元金)":balance}
    
    # 結果の表示
    print("今回の更新日: %s" % updated_date)
    print("次回の更新日: %s" % next_date)
    for k,v in contents.items():
        print("%s: %s" % (k,v))
    
    # データの保存
    with open("contents_%s.json" % updated_date, 'w') as f:
        json.dump(contents,f,ensure_ascii=False,indent=2)
    

    모처럼 얻은 데이터이므로 json으로 저장하십시오.
    몇 년 분 쌓이면, 그래프화해 보면 가계를 세우는데 도움이 될지도?

    4. 잡감



    URL과 셀렉터만 바꾸면 로봇 체크가 없는 사이트라면
    그대로 사용할 수 있으므로, 다음은 위시리스트의 가격 인하 통지에서도 만들까?

    좋은 웹페이지 즐겨찾기