当社では外国通貨の取引が多く、為替変動が収益に大きく左右します。
頻繁に為替動向をチェックしていますが、webより自動でデータを取得したいと思います。
サイトはYahoo Financeを利用します。
https://info.finance.yahoo.co.jp/history/?code=USDJPY
サイトの赤丸の欄に開始日と終了日を入力すると毎日の為替データが表示されます。
この日付指定をインプットボックスで行い、指定した期間の為替データを自動で取得してCSVファイルに保存するところまでやっていきます。
現在、CSVファイルが次のパスにあります。
ファイルには次のようにデータが自動で入ります。
それではさっそくはじめましょう。
さきほどのURLにアクセスして、開始日を2020年2月27日に指定し、終了日を2020年5月27日に指定すると、次のように4ページに分かれて毎日の為替データが表示されます。
これからやりたいことは、このそれぞれのページからデータを抽出してCSVファイルへ書き込みます。
指定した期間のデータが1ページで表示されていれば、ひとつのURLを分析すればよいのですが、いくつもページが分かれているためページごとにURLが異なっています。
よって、その4ページ分のURLをひとつのリストに入れて、for 文でそれぞれ抜き出しデータを抽出していきます。
手順
1.URLリストを作成する。
それぞれのページをリスト(URL)に入れていきます。
2.データリストを作成する。
リスト(URL)から1ページづつ抽出し、ページに表示されている為替データ
をデータリスト(USD_price)に入れていきます。
3.CSVファイルへ書き出す。
データが格納されたリスト(USD_price)からCSVファイル
(ForeignExchange_rate_USD.csv)へ書き出していきます。
手順1. URLリストを作成する
4ページそれぞれのURLは次のようになっています。
https://info.finance.yahoo.co.jp/history/?
code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=1
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=2
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=3
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=4
これをひとつのリストに入れていきます。
出来上がりは次のようになります。
['https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=1', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=2', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=3', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=4']
このurlを見てみると日付が指定されていることに気づきます。
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d
この部分に自由に数字をインプットできるようにすればよく、次のようにインプットボックスで開始日と終了日を指定できるようにします。
# インプットボックスで日付を指定します。・・①
symd = input(“スタート日を入力してください(例:2020/1/1)>”)
eymd = input(“最終日を入力してください(例:2020/12/31)>”)
# 日付を分割して変数へ入れます。・・②
SYMD = symd.split(“/”)
sy, sm, sd = SYMD
EYMD = eymd.split(“/”)・・③
ey, em, ed = EYMD
# urlを作成します。・・④
url = “https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy={}&sm={}&sd={}&ey={}&em={}&ed={}&tm=d”.format(sy,sm,sd,ey,em,ed)
ここで、コードの意味を確認しておきます。
yahoo Financeのページで、2020年2月27日から2020年5月27日のデータを取得して見ると4 ページに分かれて表示されます。
それぞれのurlは次の通りです。
1ページ目
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=1
2ページ目
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=2
3ページ目
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=3
4ページ目
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=4
それぞれのページを見比べてみると最後の” &p=〇 ” の部分だけ違っていて〇にはページ数が入っています。
次に共通部分を確認してみます。
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d
日付の指定を2020年2月27日から2020年5月27日までしましたので、このurlから次のように推測されます。
sy=開始年
sm=開始月
sd=開始日
ey=終了年
em=終了月
ed=終了日
よって、それぞれの年、月、日にインプットボックスから指定した値が入るように設定します。
① 次のようにデータを取得する期間の開始日と終了日を、インプットボックス
から取得して変数へ代入します。
symd = input(“スタート日を入力してください(例:2020/1/1)>”)
eymd = input(“最終日を入力してください(例:2020/12/31)>”)
次に、変数へ入った年月日を年、月、日に分割してそれぞれ変数へ代入します。
② 開始日を変数へ代入します。
SYMD = symd.split(“/”)
sy, sm, sd = SYMD
symdの変数には「2020/2/27」が代入されています。
split(“/”)で [‘2020’, ‘2’, ’27’] と年、月、日が区分されSYMD変数へ代入され
ます。
sy,sm,sd=SYMDにより
syには’ 2020′ が入り、sm には’ 2 ‘ が入り、sd には’ 27 ‘が入ります。
③ 次に、終了日を変数へ代入します。
EYMD = eymd.split(“/”)
ey, em, ed = EYMD
eymdの変数には「2020/5/27」が代入されています。
split(“/”)で [‘2020’, ‘5’, ’27’] と年、月、日が区分されEYMD変数へ代入され
ます。
次に、ey,em,ed=EYMDにより
eyには’ 2020′ が入り、em には’ 5 ‘ が入り、ed には’ 27 ‘が入ります。
④ 年、月、日が変数に入りましたので、これら変数をurlにフォーマットして
urlを作成します。
url = “https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy={}&sm={}&sd={}&ey={}&em={}&ed={}&tm=d”.format(sy,sm,sd,ey,em,ed)
print(url)で次のように確認ができます。
https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d
これで日付を指定したURLが取得できました。
これをコードに指定して、requestsでダウンロードしBeautifulSoupで解析してそれぞれのページのURLを取得していきます。
それでは、次のコードを書いていきます。
r = requests.get(url) #①
soup = BeautifulSoup(r.content, “html.parser”) #②
ul_elems = soup.select(“ul.ymuiPagingBottom”) #③
a_elems = ul_elems[0].select(“a”) #④
URL = [] #⑤
URL.append(url) #⑥
for elem in a_elems: #⑦
if elem.getText() != “次へ”: #⑧
href = elem.get(“href”) #⑨
URL.append(href) #⑩
print(URL)
['https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=2', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=3', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=4']
コードの意味を説明していきます。
① webサーバーからHTMLファイルをダウンロードします。
② BeautifulSoup()のかっこ内に「HTMLファイルの内容」と「パーサー」
を指定し、その結果をsoup変数に代入しておきます。
HTMLファイルの内容」は、requestsモジュールでダウンロードした結果か
ら.contentで取得できます。
③ ul要素(リスト要素)を取得して変数へ代入します。
ページの「1」のところで右クリックをして「検証」をクリックすると次のようにコードが表示されます。
これによると、ページ番号のリンクはul要素内の3つのa要素に相当することが分かります。そこで、まずul要素をclass属性の値(ymuiPagingBottom)で特定し、そこからa要素(リンク要素)を取得します。
select()メソッドによる要素の検索では、id属性とclass属性を検索条件に付加することができます。以下のように、「id属性の値」は「#」の後に、「class属性の値」は「.」の後に付け加えます。
<ul class=”ymuiPagingBottom clearFix”>
となっていますので、
soup.select(“ul.ymuiPagingBottom“)
と指定します。
④ ul要素(リスト要素)からa要素(リンク要素)を取得して、変数a_elemsへ代入します。
⑤ すべてのページのURLを格納するリスト(URL)を作ります。
⑥ ul要素を見ると、1ページ目のURLがありませんので、1ページ目のURLをリストに入れておきます。
1ページ目のURLは、「コード1」で取得した次のURLになります。
url = “https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy={}&sm={}&sd={}&ey={}&em={}&ed={}&tm=d”.format(sy,sm,sd,ey,em,ed)
⑦ ④で取得したa要素が格納されているa_elemsからひとつづつa要素を抽出し
て変数elemへ代入します。
⑧ 変数elemに代入されたa要素を読み取っていきます。
要素の内容を読み取るには、取得した要素からgetText()を呼び出します。
⑨ a要素からhref属性の値を読み取り、変数hrefへ代入します。
(href属性はリンク先の場所を示します。)
このとき「次へ」のa要素は除外します。
⑩ 変数hrefへ代入されたURLをリスト(URL)へ格納します。
次に⑦へ戻って次のa要素からhref属性を読み取りURLリストへ格納してい
きます。
すべてのa要素からhref属性を読み取りリストに格納されると、URLリストは
次のようになります。
['https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=2', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=3', 'https://info.finance.yahoo.co.jp/history/?code=USDJPY%3DX&sy=2020&sm=2&sd=27&ey=2020&em=5&ed=27&tm=d&p=4']
これで、すべてのページのURLがひとつのリストにまとまりました。
次から、このそれぞれのURLに表示されている為替データを抽出してひとつのリストにまとめていきます。
手順2 データリストを作成する。
リスト(URL)から1ページづつ抽出し、ページに表示されている為替データをデータリスト(USD_price)に入れていきます。
まずはコードから見ていきます。
# データをリストに入れていく
USD_price = [] # ①
for url in URL: # ②
# HTMLファイルのダウンロード
r = requests.get(url) # ③
# Beautiful Soup
soup = BeautifulSoup(r.content, “html.parser”) # ④
# table要素の取得
tables = soup.select(“table.boardFin”) # ⑤
# tr要素の取得
rows = tables[0].select(“tr”) # ⑥
# 各行のデータを抽出
data_list = [] # ⑦
line_num = 0 # ⑧
for row in rows: # ⑨
line_num = line_num + 1 # ⑩
# 先頭行を飛ばす
if line_num < 2: # ⑪
continue
cells = row.select(“th,td”) # ⑫
values = [] # ⑬
for cell in cells: # ⑭
values.append(cell.getText()) # ⑮
# 対象データ
datas = (values[0], values[1], values[2], values[3], values[4]) # ⑯
data_list.append(datas) # ⑰
# 確認
for data in data_list: # ⑱
USD_price.append(data) # ⑲
print(USD_price)
[('2020年5月27日', '107.520000', '107.940000', '107.350000', '107.710000'), ('2020年5月26日', '107.690000', '107.920000', '107.390000', '107.520000'), ('2020年5月25日', '107.570000', '107.770000', '107.540000', '107.690000'), ('2020年5月22日', '107.590000', '107.760000', '107.300000', '107.610000'), ('2020年5月21日', '107.480000', '107.840000', '107.460000', '107.610000'), ('2020年5月20日', '107.690000', '107.980000', '107.320000', '107.510000'), ('2020年5月19日', '107.310000', '108.080000', '107.280000', '107.680000'), ・・・・・・・・・・・・・]
では、ひとつづつ説明していきます。
① これから取得する為替データを格納するリストを作成します。
② 変数URLに入ったURLリストからひとつづつURLを抽出して変数urlへ代入
します。
③ webサーバーからHTMLファイルをダウンロードして、変数rへ代入しま
す。
④ 変数rへ代入されたurlをBeautifulSoupで読み込み、「HTMLファイルの内
容」と「パーサー」を指定し、その結果をsoup変数に代入します。
⑤ テーブル要素を取得して変数へ代入します。
webサイトの表の中で右クリックして「検証」をクリックします。
コードの次の箇所にカーソルを合わせると表が選択されることから、次のコードが表の位置を示していることがわかります。
<table width=”100%” border=”0″ cellspacing=”0″ cellpadding=”0″ class=”boardFin yjSt marB6″><tbody><tr>
table要素を取得して変数(tables)へ代入します。
table要素はいくつもあるので、特定するためにclass属性の「boardFin」で取得します。
⑥ 取得したtable要素から、「tr」要素を取得します。
tr要素は表の「行」の要素です。
すなわち、指定したtable要素の中から行を取得することになります。
このホームページにはclass属性が「boardFin」
ので、tables[0]になります。
まず、データを格納するリスト(data_list)を作成します。
その行数をカウントする変数をline_numとし、0を入れておきます。
す。
身を取り出します。
て変数datasへ代入します。
USD_priceリストへ放り込みます。
手順3.CSVファイルへ書き出す
データが格納されたリスト(USD_price)からCSVファイル
(ForeignExchange_rate_USD.csv)へ書き出していきます。
# CSVファイルへ保存する
from pathlib import Path
import csv
# CSVファイルに保存
dld_dir = Path(“./RPA”) # ①
file_path = dld_dir / “ForeignExchange_rate_USD.csv” # ②
with file_path.open(mode=”w”, encoding=”cp932″, newline=””) as f: # ③
writer = csv.writer(f) # ④
# ヘッダー
writer.writerow([“日付”, “始値”, “高値”, “安値”, “終値”]) # ⑤
# データ書き込み
for data in USD_price: # ⑥
writer.writerow(data) # ⑦
① CSVファイルが保存されているディレクトリ(RPA)をdld_dir変数へ代入し
ます。
② そのディレクトリ変数を利用して、CSVファイルのパスをfile_path変数へ
代入します。
③ CSVファイルを開きます。
mode=”w”でファイルを開きます。
open()のかっこ内にnewline=””を加えます。
(これを忘れると1行おきに空行が挿入されます。)
書き込みモード(mode=”w”)でファイルを開くと、ファイルが存在しない
場合は、新しいファイルが作成されます。ファイルがすでに存在する場合
は、上書きされます。
mode=”w”を指定した場合はファイルの中身は空になります。
mode=”w”モードを指定した場合は、ファイルを開いただけで一度空の状態
になるので注意が必要です。
(mode=”a”を指定した場合は書き込み内容が追記されます。)
「cp932」はMicrosoftがShift_JISを独自に拡張した文字コードです。
日本語版のWindows環境ではShiftJISにしておいた方が無難ですので
「cp932」を使用します。
④ CSVファイルに書き込みます。
書き込む時はCSV用のライター(writer)を作成します。
csv.writer()のかっこ内にファイルを開いた時の変数fを指定すると作成でき
ます。
⑤ ヘッダーを書き込みます。
⑥⑦ データが格納されているUSD_priceリストからデータを抽出して、
writerowで1行づつ書き込んで行きます。
以上で終了です。
為替データを取得してファイルに書き込んだだけでは自動化の意味はあまりありませんが、このデータを分析・加工し、またグラフにしてパワーポイントに表示するところまで自動で仕上げれば、報告用の資料を作成する時間はだいぶ縮小されます。