この記事について
関西ショアジギングの聖地、武庫川一文字(通称武庫一)における2007年から2022年現在までの釣果をスクレイピングから可視化分析まで行った。結果だけ見たい方はこちら。
環境
WSL2 Ubuntu18.04
vsCode
モジュールインポート
import itertools
import pandas as pd
import chromedriver_binary
from selenium import webdriver
定数
釣果表と日付選択後表示するボタンは事前にブラウザ上でXpathを確認。
TABLE = "/html/body/center/table/tbody/tr[12]/td"
DISPLAY = "/html/body/center/table/tbody/tr[12]/td/table[2]/tbody/tr[1]/td[2]/button"
ZEN = "/()0123456789"
HAN = "/()0123456789"
スクレイピング
ポイントは以下の3点。
1. ページ間移動
月日を選択することで釣果のテーブルが表示されるため、月日の選択と表示ボタンの押下をselenium経由で実行する必要がある。
years = web_driver.find_element(By.NAME, "year")
year_select = Select(years)
year_select.select_by_value(str(year))
months = web_driver.find_element(By.NAME, "month")
month_select = Select(months)
month_select.select_by_value(str(month).zfill(2))
display_button = web_driver.find_element(By.XPATH, DISPLAY)
display_button.click()
2. 釣果なしでもページはある
2007年9月まではページ自体は存在する(選択できる)が釣果はない。また、釣果があった日のみ掲載があるため、read_htmlとして読み込んだ後、日付行を検索して取得する必要がある。
if len(dfs) != 0: #釣果のない年月は取得しない
3. 異なるテーブル行
日付、釣果状況コメント欄が混在するため、釣果テーブル自体の列数が行ごとに異なる。
if (len(df.columns) == 10) and (len(df) > 1): # 釣果行のみ取得、かつ釣果があるか
以上を踏まえて
import itertools
import pandas as pd
from selenium import webdriver
import chromedriver_binary
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
URL = "釣果HPのアドレス"
TABLE = "/html/body/center/table/tbody/tr[12]/td"
DISPLAY = "/html/body/center/table/tbody/tr[12]/td/table[2]/tbody/tr[1]/td[2]/button"
ZEN = "/()0123456789"
HAN = "/()0123456789"
def to_hankaku(s):
return s.translate(str.maketrans(ZEN, HAN))
def trim_dow(s):
return s.split("(")[0]
web_driver = webdriver.Chrome()
web_driver.get(URL)
monthly_dfs = []
for year, month in itertools.product(
list(range(2007, 2023)), list(range(1, 13))):
daily_dfs = []
print(year, "/", month)
years = web_driver.find_element(By.NAME, "year")
year_select = Select(years)
year_select.select_by_value(str(year))
months = web_driver.find_element(By.NAME, "month")
month_select = Select(months)
month_select.select_by_value(str(month).zfill(2))
display_button = web_driver.find_element(By.XPATH, DISPLAY)
display_button.click()
elem_table = web_driver.find_element(By.XPATH, TABLE)
html = elem_table.get_attribute('innerHTML')
dfs = pd.read_html(html, header=0)
if len(dfs) != 0: # 釣果のない年月は取得しない
for i, df in enumerate(dfs):
if (len(df.columns) == 10) and (len(df) > 1): # 釣果行のみ取得、かつ釣果があるか
date_str = df[df["Unnamed: 0"] == "日付"].iat[0, 1]
df["Year"] = year
df["Month"] = month
df["Day"] = int(trim_dow(to_hankaku(date_str)).split("/")[-1])
if len(df) != 0:
daily_dfs.append(df)
if daily_dfs:
monthly_dfs.append(pd.concat(daily_dfs))
else:
web_driver.back()
web_driver.close()
df = pd.concat(monthly_dfs)
df.to_csv("chouka.csv", index=False)
続きは
データクレンジング編
データ分析編