# 倒産情報当月公表分・定時自動取得&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")