# 倒産情報当月公表分・定時自動取得&SQLITE連動&メール配信V1.4_221111
# 1:JCnetで掲示される倒産全国および小口倒産ページから情報取得。
# 2:1件抽出ごとに過去記録有無を確認し、新規分のみを対象情報とする。
# 3:注目項目として「areaが"大阪"もしくは"堺市"もしくは"東大阪"を含む」とする。
# 4:東大阪市案件は特別に注目する。
# 5:1件抽出ごとに注目項目の該当是非を確認し、該当の場合、所定マークを得る。
# 6:対象情報1件ごとに所定マークを含めた追記情報をDBに追記する。
# 7:追記情報のうち、所定マークのある分だけをメール文に追記する
# 8:メール文を所定アドレスから所定アドレスへ送信する ■V1.4:該当がない場合、送信しない。
# 上記1~8を子プロセスとし、所定時刻に実行させる。
# 所定時刻は、毎日8:30、12:30、16:45に固定する。
#
# 倒産情報dbは下記構造とする。
# CREATE TABLE "倒産情報" (
#    "area"            TEXT,
#    "date"            TEXT,
#    "num_kiji"        TEXT,
#    "type"            TEXT,
#    "title"            TEXT,
#    "content"            TEXT,
#    "mark_attention"        TEXT,
#    "mark_higashiosaka"    TEXT,
#    "year_kiji"        INTEGER,
#    "month_kiji"        INTEGER,
#    "timestamp_record"    TEXT,
#    "timestamp_mailsent"    TEXT,
#    "comment"        TEXT
#    "url"        TEXT
#
#
#CREATE TABLE "list_attention" (
#    "index_list"    INTEGER,
#    "attention"    TEXT
#)
# スケジュール実行対象関数の定義
def task():
    # 休日判定ライブラリをインポート
    import jpholiday
    import datetime
    from time import sleep
    # DATE = "yyyymmdd" # 日付は8桁文字列の形式
    # <休日動作テスト用
    #DATE_dummy = "20220811"
    #Date_dummy = datetime.date(int(DATE_dummy[0:4]), int(DATE_dummy[4:6]), int(DATE_dummy[6:8]))
    # date_today = Date_dummy

    # 今日の日付取得
    date_today = datetime.date.today()
    # 曜日の取得(0:月曜、4:金曜、5:土曜、6:日曜)
    day_otw =  date_today.weekday()
    # 祝日是非取得(True:祝日、False:平日)
    jph = jpholiday.is_holiday(date_today)    
    #
    #平日(土日祝日以外)に下記を実行する
    if day_otw <= 4 and jph == False :
        #
        # メール送信関連設定
        import smtplib
        from email.mime.text import MIMEText
        from email.header  import Header
        # from typing_extensions import dataclass_transform
        #ユーザネーム、パスワード、送信元メールアドレス、宛先メールアドレスの設定
        # Gmailにアスセスするパスワードではなく、Gmailアカウントのセキュリティで取得したAPW(アプリパスワード)を使う
        # アプリパスワード取得には2段階認証がONでなければならない。
        # アプリパスワードは同じデバイスの同じアカウントに対して有効。すなわち別のPCなら別のAPWが必要になる
        username = 'shienkiko11hispa@gmail.com'
        password = 'avleojinbopbmgzu'
        from_address = 'shienkiko11hispa@gmail.com'
        #to_address = 't-hasegawa@hispa.biz-web.jp'
        #to_address="t-hasegawa@hispa.biz-web.jp,toruhasegawa23@gmail.com"
        to_address="t-hasegawa@hispa.biz-web.jp,toruhasegawa23@gmail.com,nobuyuki-madokoro@city.higashiosaka.lg.jp"
        # 送信時は宛先のリストを引数にする
        sendToList = to_address.split(',')

        # データ処理系ライブラリ設定
        import pandas as pd
        import csv
        import datetime
        import time
        from time import sleep
        # SQLiteライブラリ
        import sqlite3

        # HTML処理系ライブラリ設定
        # import requests #CJnetページはrequestsを跳ね返すのでseleniumで入るしかない。
        from bs4 import BeautifulSoup

        # Import selenium library and set Cromedriver
        import selenium
        from selenium import webdriver
        # Chromedriver設定
        
        #エラー回避処理 効果なし!230704
        #from selenium.webdriver.chrome.service import Service
        #from selenium.webdriver.chrome.options import Options
        #options = Options()
        #options.add_argument('--ignore-certificate-errors')
        #url_driver = 'C:/Users/shienkikou11/Desktop/VSCode/chromedriver.exe'
        
        url_driver = 'C:/Users/shienkikou11/Desktop/VSCode/chromedriver.exe'
        driver = webdriver.Chrome(url_driver)

        # 現在時刻の取得
        dt_now = datetime.datetime.now()
        print("Process Start at ",dt_now)
        # 現在年・月の文字列取得・・・サマリーURL設定に用いる
        year_search=str(dt_now.year)
        month_search=f'{dt_now.month:02}'

        # 倒産情報dbをデータフレームに読込
        #file_db = "C:/Users/shienkikou11/Desktop/VSCode/倒産情報.db"
        file_db = "C:/Users/shienkikou11/Desktop/VSCode/倒産情報test.db"
        conn = sqlite3.connect(file_db)
        df=pd.read_sql_query('SELECT * FROM 倒産情報', conn)
        # 倒産情報dbの記事番号リストの取得
        df_num_kiji = df["num_kiji"]
        list_num_kiji = df_num_kiji.values.tolist()
        # 倒産情報dbのタイトルリストの取得
        df_title = df["title"]
        list_title = df_title.values.tolist()
        #注目区域のリストの取得
        conn = sqlite3.connect(file_db)
        df=pd.read_sql_query('SELECT * FROM list_attention', conn)
        df_attention = df["attention"]
        list_attention = df_attention.values.tolist()
        area1 = list_attention[0] 
        area2 = list_attention[1] 
        area3 = list_attention[2] 

        conn.close()

        # 倒産情報ページURL設定
        # URLをリストで表記。CSVから読まず、直接リストに追記。CSV作るほどの内容ではない。
        # 2021年7月12日以前はarea情報が<>ではなく()で表記され、同時に(株)が存在するため、このコードでは対応できない。

        target_urls = []
        url_head = 'https://n-seikei.jp/'
        # url = url_head+year_search+"/"+month_search+"/" #アーカイブページが読めなくなった
        # url = url_head+year_search+"/"+month_search+"/"
        url = url_head+"tousan/"  # 倒産全国ページで見る
        target_urls.append(url) 
        url = url_head+"koguchi-hasan/"  # 小口倒産・破産開始ページで見る
        target_urls.append(url) 

        #  メール本文(文字列)のイニシャライズ
        text_mail=""
        # データベースに追記するためのリストのリストをクリアする
        lists_data = []

        # 倒産情報ページ(当月アーカイブ)読込
        for target_url in target_urls:
            
            # Chromeのインスタンス画面を開く
            error_flg = False
            driver.get(target_url)  
            sleep(5)

            # インスタンス画面のHTMLソースを読み、HTMLを整える
            page_source = driver.page_source
            soup = BeautifulSoup(page_source, 'html.parser')

            # 倒産情報記事部分を抜き出し、リストにする
            elements = soup.find_all(class_="entry-c")
            len_elements = len(elements)
            # print("情報数=",len_elements) #記事数。デバッグ時のみ使用
            #for element in elements #この形式のほうが理想的だが、デバッグ用に件数抑え込みでiを使った。本番も問題なく動くので放置
            for i in range(0,len_elements):
                element = elements[i]
                #記事の種類を取得
                element_type = element.find("img").get("alt")
                #記事タイトルを取得
                element_title = element.find("a").text
                #記事URLを取得
                element_href = element.find("a").get("href")
                #記事URLに「post」が含まれる場合、記事番号を取得、含まれない場合は「XXXXXX」を記事番号に代入+++
                if "post" in element_href:
                    element_num_kiji = element_href.split("post-")[1].replace(".html","")
                else:
                    element_num_kiji = "XXXXXX"

                #記事本文を取得、メール用の不整文字を処理(除去、変換)
                element_kiji = element.find("div",class_="entry-content-c clearfix").text.replace('\n','').replace(' ','').replace(' ','').replace('    ','')
                element_kiji = element_kiji.replace('・・・続きを読む','').replace('...','').replace('官報より参照。','').replace('\xa0',"")
                element_kiji = element_kiji.replace('\xa0',"")
                element_kiji = element_kiji.replace('\uff0d',"-")

                #記事日付を取得、括弧を除去
                element_date = element.find_all("div")[2].text.replace("[ ","").replace(" ]","")

                # 記事番号がXXXXXXでない場合
                if element_num_kiji != "XXXXXX":
                    # 記事番号リストから同一記事番号の数を算出
                    check_old_num_kiji = list_num_kiji.count(element_num_kiji)
                    # 過去記録に同一記事番号がなければ新規レコードフラグ="Y"とする
                    if check_old_num_kiji == 0:
                        element_flag_record = "Y"
                    # 過去記録に同一記事番号があれば、新規レコードフラグ="n"とする
                    else:
                        element_flag_record = "n"
                # 記事番号がXXXXXXの場合、
                else:
                    # タイトルリストに同一タイトルの数を算出
                    check_old_title = list_title.count(element_title)
                    # 同一タイトルがなければ新規レコードフラグ="Y"とする
                    if check_old_title == 0:
                        element_flag_record = "Y"
                    #同一タイトルがあれば、新規レコードフラグ="n"とする
                    else:
                        element_flag_record = "n"

                # 新規レコードの場合のみ、倒産情報dbの倒産情報テーブルへ追記、メール文を作成
                if element_flag_record == "Y":
                    mark_attention = "n"
                    mark_higashiosaka = "n"
                    # 記事タイトル中の<>に囲まれた文字列をareaとし、所定の注目区域の場合にマークを打つ
                    # area1 = "東大阪"、area2 = "大阪"、area3 = "堺市"・・・これらはDBから読出、設定されている
                    if "<" in element_title and ">" in element_title:
                        area = element_title.split("<")[1].split(">")[0]
                    else:
                        area = "Others"
                    if area != "Others":
                        if area1 in area or area2 in area or area3 in area:
                            mark_attention = "Y"
                            # 記事中にarea1("東大阪”)があれば専用マークに"227"を打つ。227は大阪府東大阪市の市区番号
                            if area1 in element_kiji:
                                mark_higashiosaka = "227"
                                #記事が東大阪市案件の場合、注目するための記述と改行を追加
                                text_mail=text_mail+"■"+element_type+" "+area+" "+element_date+" "+element_num_kiji+" ★★★東大阪市"+"\n"
                            else:
                                text_mail=text_mail+"■"+element_type+" "+area+" "+element_date+" "+element_num_kiji+"\n"
                            #記事タイトルと改行を追記
                            text_mail=text_mail+element_title+" "+element_href+"\n"
                            #記事本文と改行を追記
                            text_mail=text_mail+element_kiji+"\n"
                    #
                    
                    # データベースに追記するレコード(リスト)を生成
                    data=[]
                    dt_now = datetime.datetime.now()
                    #記事の年度を設定
                    year_kiji = dt_now.year
                    #記事の月度を設定
                    month_kiji = dt_now.month
                    #レコード記録のタイムスタンプを設定
                    timestamp_record = dt_now
                    # mark_attentionが"Y" もしくは mark_higashiosakaが"227"ならば・・・
                    if mark_attention=="Y" or mark_higashiosaka=="227":
                        # timestamp_mailsentをtimestamp_recordにする
                        timestamp_mailsent = timestamp_record
                    else:
                        #そうでなければtimestamp_mailsentを””にする 
                        timestamp_mailsent = ""
                    #DBのコメント欄に文字列NULLを代入(すべてのレコード)。コメント欄への記入はDB上で直接行う。
                    comment="NULL"
                    #DBのレコードにまとめ追記するためのリストを作成
                    data=[area,element_date,element_num_kiji,element_type,element_title,element_kiji,mark_attention,mark_higashiosaka,year_kiji,month_kiji,timestamp_record,timestamp_mailsent,comment,element_href]
                    #「レコード追記リストのリスト」に上記リストを追加
                    lists_data.append(data)
        # Chormeのインスタンス画面を閉じる
        driver.close()
                               
        # 倒産情報dbの倒産情報テーブルへの追記
        # 倒産情報db倒産情報テーブルに接続するオブジェクトを作る
        conn = sqlite3.connect(file_db)
        # テーブル構造を取得するため1件だけ取得してみる
        df = pd.read_sql_query(sql=u"SELECT * FROM 倒産情報 LIMIT 1", con=conn)
        # INSERTするレコード(リスト)のリストをデータフレームに入れる
        df_ins = pd.DataFrame(lists_data, columns=df.columns)
        # データ追加(レコード登録)のINSERT文を実行する
        df_ins.to_sql(u"倒産情報", conn, if_exists='append', index=None)
        # レコード追加を確定(確定しないとトランザクションが成立しない、すなわちそのレコードは消える)
        conn.commit()
        # 倒産情報db倒産情報テーブルへの接続を閉じる
        conn.close()
                    

        # メール送信・・・注目点がなくてもメールを打つ。
        if len(text_mail) == 0:
            #text_mail = "前回メール以降に、大阪府、堺市、東大阪市に関連する「新たな倒産情報」はありませんでした。"
            print("append DB but passed mail due to no attention for Osaka")
        else:
            # MIMETextオブジェクトの生成
            charset = 'iso-2022-jp'
            date_title = str(dt_now)[0:16]
            subject = '倒産情報'+date_title
            # メールオブジェクトの生成
            # 不整文字の除去
            text_mail = text_mail.replace('\xa0',"").replace('\uff0d',"-").replace('\uff5e', '')
            # msg_mail = MIMEText(text_mail, 'html', charset)  
            msg_mail = MIMEText(text_mail, 'plain', charset)  
            msg_mail['Subject'] = Header(subject, charset)
            msg_mail['From'] = from_address 
            msg_mail['To'] = to_address 
            # SMTPサーバへの接続、暗号化、ログイン、送信、切断
            server = smtplib.SMTP('smtp.gmail.com', 587)
            server.starttls()
            server.login(username, password)
            #print("mail-sending-start")
            server.sendmail(from_address, sendToList, msg_mail.as_string())
            server.quit()
            # 末文
            print("append DB and send mail Process End")
#
print("task start")
# ワンショット
task()
print("task end")