JFLランキング作成(GoogleDrive)

pip3 install pandas
pip3 install beautifulsoup4
pip3 install html5lib
pip3 install lxml
pip3 install gspread
pip3 install oauth2clinet
pip3 install tqdm
# -*- coding: utf-8 -*-

import gspread
import pandas as pd
import requests
from bs4 import BeautifulSoup
from oauth2client.service_account import ServiceAccountCredentials

url = "http://www.jfl.or.jp/jfl-pc/view/s.php?a=1411&f=2019A001_spc.html"

dfs = pd.read_html(url, na_values="-")

print(len(dfs))


dfs_h = []

for i in dfs:
    i.columns = ["日にち", "時間", "ホーム", "スコア", "アウェイ", "スタジアム", "備考"]
    dfs_h.append(i)


df = pd.concat(dfs_h, keys=[i for i in range(1, len(dfs_h) + 1)], names=["節", "番号"])


# 備考を除去
df.drop("備考", axis=1, inplace=True)

# スコアがないものを除去
df.dropna(subset=["スコア"], inplace=True)

# スコアを分割
df2 = df["スコア"].str.split("-", expand=True)
df2 = df2.astype(int)
df2.columns = ["ホーム得点", "アウェイ得点"]

# スコアを削除
df1 = df.drop("スコア", axis=1)

# スコアを分割、スコアを削除、結合
df = pd.concat([df, df2], axis=1)

# ホーム
df_home = df.loc[:, ["ホーム", "アウェイ", "ホーム得点", "アウェイ得点"]].reindex()
df_home.columns = ["チーム名", "対戦相手", "得点", "失点"]
df_home["戦"] = "H"
df_home.head()

# アウェイ
df_away = df.loc[:, ["アウェイ", "ホーム", "アウェイ得点", "ホーム得点"]]
df_away.columns = ["チーム名", "対戦相手", "得点", "失点"]
df_away["戦"] = "A"
df_away.head()

df_total = pd.concat([df_home, df_away])


# 得失点を計算
df_total["得失点"] = df_total["得点"] - df_total["失点"]
df_total.head()


# 勝敗を追加
def win_or_loss(x):
    if x["得点"] > x["失点"]:
        return "勝利"
    elif x["得点"] < x["失点"]:
        return "敗戦"
    else:
        return "引分"


df_total["勝敗"] = df_total.apply(lambda x: win_or_loss(x), axis=1)


# 勝点を追加
def win_point(x):
    if x["得点"] > x["失点"]:
        return 3
    elif x["得点"] < x["失点"]:
        return 0
    else:
        return 1


df_total["勝点"] = df_total.apply(lambda x: win_point(x), axis=1)

# 得点・失点・得失点・勝点 集計
pv_score = df_total.pivot_table(
    values=["得点", "失点", "得失点", "勝点"], index="チーム名", aggfunc=sum
)


# 集計用にカウント追加
df_total["カウント"] = 1

# 得点・失点・得失点・勝点 集計
pv_wlcnt = df_total.pivot_table(
    values="カウント", index="チーム名", columns=["戦", "勝敗"], aggfunc=sum, fill_value=0
)


# 列名変更
pv_wlcnt.columns = ["勝利A", "引分A", "敗戦A", "勝利H", "引分H", "敗戦H"]

# 合計追加
pv_wlcnt["勝利"] = pv_wlcnt["勝利H"] + pv_wlcnt["勝利A"]
pv_wlcnt["引分"] = pv_wlcnt["引分H"] + pv_wlcnt["引分A"]
pv_wlcnt["敗戦"] = pv_wlcnt["敗戦H"] + pv_wlcnt["敗戦A"]

# 試合数追加
pv_wlcnt["試合数"] = pv_wlcnt["勝利"] + pv_wlcnt["引分"] + pv_wlcnt["敗戦"]


df3 = df_total.copy()

# 評価値を作成
df3["評価値"] = (df3["勝点"] * 10000) + (df3["得失点"] * 100) + df3["得点"]


# 評価値集計
pv_eval = df3.pivot_table(
    values="評価値", index="チーム名", columns="節", aggfunc=sum, fill_value=0
)


# 累計評価値
pvc_eval = pv_eval.apply(lambda d: d.cumsum(), axis=1)


# 累計評価値をランキングに変換
df_rank = pvc_eval.rank(ascending=False, method="min").astype(int)
df_rank

# 前ランキングとの差分
df4 = df_rank.copy()
df_diff = df4.diff(axis=1).fillna(0)


# 差分を三角に変換
def arrow_up(x):
    if x > 0:
        return "▼"
    elif x < 0:
        return "▲"
    else:
        return "-"


s1 = df_diff.iloc[:, -1].apply(lambda x: arrow_up(x))
s1.name = "前節"


df5 = pd.concat([pv_score, pv_wlcnt], axis=1).join(s1)


# 評価値を作成
df5["評価値"] = (df5["勝点"] * 10000) + (df5["得失点"] * 100) + df5["得点"]

# ランキング
df5["順位"] = df5["評価値"].rank(ascending=False, method="min").astype(int)

# 順位で昇順
df5.sort_values(["順位"], inplace=True)


# チーム名をインデックスから解除
df6 = df5.reset_index()
jfl_rank = df6.loc[
    :,
    [
        "前節",
        "順位",
        "チーム名",
        "勝点",
        "試合数",
        "勝利",
        "勝利H",
        "勝利A",
        "引分",
        "引分H",
        "引分A",
        "敗戦",
        "敗戦H",
        "敗戦A",
        "得失点",
        "得点",
        "失点",
    ],
]


# 結果を追加
def match_result(x):
    if x["得点"] > x["失点"]:
        return "{}○{}".format(x["得点"], x["失点"])
    elif x["得点"] < x["失点"]:
        return "{}●{}".format(x["得点"], x["失点"])
    else:
        return "{}△{}".format(x["得点"], x["失点"])


df_total["結果"] = df_total.apply(lambda x: match_result(x), axis=1)


# 戦績表 集計
pv_senseki = df_total.pivot_table(
    values="結果", index=["チーム名", "戦"], columns="対戦相手", aggfunc=sum, fill_value=""
)


jfl_team = [
    "Honda FC",
    "FC大阪",
    "ソニー仙台FC",
    "FC今治",
    "東京武蔵野シティFC",
    "MIOびわこ滋賀",
    "奈良クラブ",
    "ヴェルスパ大分",
    "ラインメール青森",
    "ヴィアティン三重",
    "テゲバジャーロ宮崎",
    "FCマルヤス岡崎",
    "ホンダロックSC",
    "流経大ドラゴンズ龍ケ崎",
    "松江シティFC",
    "鈴鹿アンリミテッド",
]

new_idx = pd.MultiIndex.from_product(
    [jfl_team, ["H", "A"]], names=pv_senseki.index.names
)

jfl_senseki = pv_senseki.reindex(new_idx, columns=jfl_team)
jfl_senseki.fillna("", inplace=True)


# スプレッドシート

scope = [
    "https://spreadsheets.google.com/feeds",
    "https://www.googleapis.com/auth/drive",
]

credentials = ServiceAccountCredentials.from_json_keyfile_name(
    "jfl-ranking.json", scope
)
gc = gspread.authorize(credentials)

workbook = gc.open_by_key("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

# ランキング更新

rank_data = jfl_rank.values.flatten().tolist()

worksheet = workbook.worksheet("ランキング")

cell_list = worksheet.range("A2:Q17")

for cell, v in zip(cell_list, rank_data):
    cell.value = v

worksheet.update_cells(cell_list)

# 戦績表更新

senseki_data = jfl_senseki.values.flatten().tolist()

worksheet = workbook.worksheet("戦績表")

cell_list = worksheet.range("C2:R33")

for cell, v in zip(cell_list, senseki_data):
    cell.value = v

worksheet.update_cells(cell_list)

# 順位を取得

imabari = df5.at['FC今治', '順位']
imabari


# url = 'http://www.jfl.or.jp/jfl-pc/view/s.php?a=1436&f=2019A00106_spc.html'
url = 'http://www.jfl.or.jp/jfl-pc/view/s.php?a=871&f=top_spc.html'

headers = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
}

r = requests.get(url, headers=headers)
soup = BeautifulSoup(r.content, 'html5lib')

for i in soup.select('table.score-table'):

    team = [
        j.get_text(strip=True)
        for j in i.select('tr:nth-of-type(2) > th[class^="score-team"]')
    ]

    score = [j.text for j in i.select('tr:nth-of-type(2) > td.score-finish')]

    if 'FC今治' in team:

        # スコアを数字に変換
        temp = list(map(int, score))

        # ホーム
        if 'FC今治' in team[0]:

            place = 'ホーム'
            opponent = team[1]
            home = temp[0]
            away = temp[1]

        # アウェイ
        else:

            place = 'アウェイ'
            opponent = team[0]
            home = temp[1]
            away = temp[0]

        # 勝利
        if home > away:

            res = '勝利しました'

        # 敗北
        elif home < away:

            res = '負けました'

        # 引分
        else:

            res = '引分ました'

        print(
            '今日の{0}との{1}戦は{2}-{3}で{4}\n現在の順位は{5}位です\n#FC今治\nhttps://docs.google.com/spreadsheets/d/e/2PACX-1vRHxFkvm1VLkykuCINoEmRHIfPE5gJB_Jb6uUsrS0lXdlg354HC_AEwnNQD_TAlgC3v1yFfFNW4ETpD/pubhtml'
            .format(opponent, place, home, away, res, imabari))
        break

Pandasで愛媛の河川の水位を取得

2021/04/18現在利用できません

github.com

import datetime
import time

import pandas as pd
from tqdm import tqdm


# 時間
def timeconv(x):
    H, M = map(int, x.split(":"))
    return datetime.timedelta(hours=H, minutes=M)


# 設定
# 東予東部 grp, tpg = "USR019", 2
# 東予西部 grp, tpg = "USR020", 1
# 中予     grp, tpg = "USR021", 2
# 南予北部 grp, tpg = "USR022", 2
# 南予南部 grp, tpg = "USR023", 2

grp, tpg = "USR020", 1

# 期間(2019/04/25 00:10 ~ 2019/04/27 00:00)
period = pd.date_range("2019-04-27 04:00:00", "2019-05-01 00:00:00", freq="4H")

# 結果
result = []

for i in tqdm(period):

    # 時間調整
    dt = i - datetime.timedelta(hours=4)

    tmp = []

    for pg in range(1, tpg + 1):

        url = "http://183.176.244.72/cgi/050_HQ_030_01.cgi?GID=050_HQ_030&UI=U777&SI=00000&LO=88&SRO=1&KKB=101100&DSP=11110&SKZ=111&NDT=1&MNU=1&BTY=IE6X&SSC=0&RBC=100&DT={0}&GRP={1}&TPG={2}&PG={3}&KTM=3".format(
            i.strftime("%Y%m%d%H%M"), grp, tpg, pg
        )

        # ダム情報をスクレイピング
        river = pd.read_html(url, na_values=["欠測", "−", "閉局"])

        # タイトル
        name = river[0].iloc[0, :].dropna().tolist()

        # データ個数
        n = len(name)

        # データを結合
        data = pd.concat([pd.concat(i, axis=1) for i in zip(*[iter(river[5:])] * n)])

        # 列名を登録
        data.columns = ["日付", "時間"] + name[1:]

        # 日付を補完
        data["日付"].fillna(method="ffill", inplace=True)

        # 日付と時間から年を補完し、日時を作成
        data["日時"] = pd.to_datetime(data["日付"], format="%m/%d").apply(
            lambda x: x.replace(year=dt.year)
        ) + data["時間"].apply(timeconv)

        # 日付と時間を削除
        data.drop(["日付", "時間"], axis=1, inplace=True)

        # 日時をインデックス
        data.set_index("日時", inplace=True)

        tmp.append(data)

        # スリープ
        time.sleep(3)

    # 結果を保存
    result.append(pd.concat(tmp, axis=1))

# 結果を結合
df = pd.concat(result)
df

# 矢印除去
df2 = df.applymap(lambda x: x.rstrip("↑↓→") if type(x) is str else x ).astype(float)

# 欠損確認
df2[df2.isnull().any(axis=1)]

df2.info()

# 欠損値を補完
# df2.fillna(method="ffill", inplace=True)
# df2.fillna(method="bfill", inplace=True)

df2.plot(figsize=(15, 5))

Pandasで愛媛のダム情報を取得

2021/04/18現在利用できません

github.com

import datetime
import time

import pandas as pd
from tqdm import tqdm

# 時間
def timeconv(x):
    H, M = map(int, x.split(":"))
    return datetime.timedelta(hours=H, minutes=M)

# GRP = USR004:玉川ダム、USR005:台ダム、USR010:鹿野川ダム、USR011:野村ダム
grp = "USR004"

# 期間(2019/04/25 00:10 ~ 2019/04/27 00:00)
period = pd.date_range("2019-04-25 04:00:00", "2019-04-27 00:00:00", freq="4H")

# 結果
result = []

for i in tqdm(period):

    url = "http://183.176.244.72/cgi/170_USER_010_01.cgi?GID=170_USER_010&UI=U777&SI=00000&MNU=1&LO=88&BTY=IE6X&NDT=1&SK=0000000&DT={0}&GRP={1}&TPG=1&PG=1&KTM=3".format(
        i.strftime("%Y%m%d%H%M"), grp
    )

    # 時間調整
    dt = i - datetime.timedelta(hours=4)

    # ダム情報をスクレイピング
    dam = pd.read_html(url, na_values=["欠測", "−"])

    # データを結合
    data = pd.concat([pd.concat(i, axis=1) for i in zip(*[iter(dam[4:])] * 6)])

    # 列名を登録
    data.columns = ["日付", "時間", "貯水位", "全流入量", "全放流量", "貯水量", "貯水率"]

    # 日付を補完
    data["日付"].fillna(method="ffill", inplace=True)

    # 日付と時間から年を補完し、日時を作成
    data["日時"] = pd.to_datetime(data["日付"], format="%m/%d").apply(lambda x: x.replace(year=dt.year)) + data["時間"].apply(timeconv)

    # 日付と時間を削除
    data.drop(["日付", "時間"], axis=1, inplace=True)

    # 日時をインデックス
    data.set_index("日時", inplace=True)

    # 結果を保存
    result.append(data)

    # スリープ
    time.sleep(3)

# 結果を結合
df = pd.concat(result)
df

# 欠損確認
df[df.isnull().any(axis=1)]

df.info()

# 欠損値を補完
# df.fillna(method="ffill", inplace=True)
# df.fillna(method="bfill", inplace=True)

df[["貯水位", "貯水量"]].plot(secondary_y=["貯水量"], figsize=(10, 5))

df[["全流入量", "全放流量", "貯水量"]].plot(secondary_y=["貯水量"], figsize=(10, 5))

DAZNのエラーコード「65-013-403」

このコンテンツはこちらの地域ではご利用できません。

auひかりのdionで発生(4月)

エラー「65-013-403」

【結論】DAZNに問い合わせをして解除してもらう

問い合わせ先

twitter.com

my.dazn.com

f:id:imabari_ehime:20190422223307p:plain

確認

  • モバイルで動画を見ることができません

https://my.dazn.com/help/video-trouble-on-mobile-jp

  • パソコンで動画を見ることができません

https://my.dazn.com/help/video-trouble-on-internet-jp

IP確認

国内からのアクセスか確認

whatismyipaddress.com

結果

機械 通信手段 場所 状況
iPhone モバイル通信 国内
iPhone 自宅Wi-Fi 国内 ×
iPhone 自宅Wi-Fi+Wi-Fiセキュリティ 海外
Fire TV 自宅Wi-Fi 国内 ×

st.pass.auone.jp

※保護をONにするとVPN接続で海外からのアクセスになります。 次の日からWi-Fiセキュリティでの接続もエラー

「10-006-002」

恐れ入りますが、お客様のいらっしゃる国ではDAZNをご利用いただけません。

f:id:imabari_ehime:20190422225734j:plain

試したこと

  • モデム・ルーターの再起動 ※auひかりはIPが変わりません
  • Fire TVを再起動
  • Fire TVのDAZNのキャッシュを削除
  • (試していない)Fire TVのDAZNアプリを再インストール

まとめ

IPにより地域を特定しているため機械等を変更してもエラーがでます。

モバイル通信またはVPN等でIPアドレスが変わると見れます。

VPNの接続制限(ブロッキング)について

https://my.dazn.com/help/vpn-blocking-jp

DAZNVPNでの使用を止めた理由は何ですか? DAZNはサービスが展開された国内でのみ、ご使用いただけます。DAZNの配信コンテンツ(スポーツ)は、配信可能な国において厳格な管理がなされています。そのため、国外からDAZNの視聴を試みているユーザーへのアクセスを制限する必要があります。

DAZNにアクセスできず、ブロックされているようですが、VPNは使用していません。 ご使用されているインターネットサービスプロバイダにお問い合わせください。

モバイル通信およびVPN(海外)からはアクセスできるため国内プロバイダからのアクセスを間違ってDAZNがアクセスを制限がしている可能性が高い。

https://my.dazn.com/help/different-country-jp

NURO光をご利用のお客様へ 現在のところ、ご利用のIPアドレスにおきまして、海外と判断されてしまうお客様がいらっしゃいます。大変恐れ入りますが、NURO光サービスにおきまして、IPアドレスが日本国内のものと判断されるか、ONUの再起動を繰り返し行なっていただくよう、お願い申し上げます。

プロバイダ単位ではなくIP単位(市内のauひかりユーザーは普通に見れています)

広島カープの試合は、一部地域にてご視聴いただけない場合がございます。あらかじめご了承下さい。

時期的に4月からなのでこれが違うコンテンツにも適応されているのかもしれません。

DAZNの制限が解除されないかぎり解決にはならないため問い合わせが必要です。

JFLの速報をスクレイピング

import requests
from bs4 import BeautifulSoup

# url = 'http://www.jfl.or.jp/jfl-pc/view/s.php?a=1436&f=2019A00101_spc.html'
url = 'http://www.jfl.or.jp/jfl-pc/view/s.php?a=871&f=top_spc.html'

headers = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
}

r = requests.get(url, headers=headers)
soup = BeautifulSoup(r.content, 'html5lib')

for i in soup.select('table.score-table'):

    team = [
        'Honda FC' if 'Honda FC' in j.text else j.text
        for j in i.select('tr:nth-of-type(2) > th[class^="score-team"]')
    ]

    score = [j.text for j in i.select('tr:nth-of-type(2) > td.score-finish')]

    print(f'{team[0]: >11} {score[0]} - {score[1]} {team[1]}')

Ubuntu18.04にDokkuをインストール

computingforgeeks.com

knowledge.sakura.ad.jp

shokai.org

qiita.com

# ホスト名設定
hostnamectl set-hostname dokku.192.168.0.100.xip.io

# ホスト名登録
sudo nano /etc/hosts
192.168.0.100 dokku.192.168.0.100.xip.io dokku

# GPGキーを登録
# E: This command can only be used by root
# エラーがでるのでrootでインストール

sudo su
wget -nv -O - https://packagecloud.io/gpg.key | apt-key add -
exit

# リポジトリを登録

sudo nano /etc/apt/sources.list.d/dokku.list
deb https://packagecloud.io/dokku/dokku/ubuntu/ bionic main

# Docker Engineをインストール

wget -nv -O - https://get.docker.com/ | sh

# Dokku インストール

sudo apt update && sudo apt upgrade
sudo apt install dokku

# インストール確認

id dokku
ls -la /home/dokku/

# サービス確認

systemctl status dokku-installer.service

# サービスが自動起動か確認

systemctl is-enabled dokku-installer.service

# バージョン確認

dokku version

# コア依存関係を設定

dokku plugin:install-dependencies --core


---

# アップデート

dokku-update

# 再構築

dokku ps:rebuildall