米国株価を泥臭くスクレイピングする
スクレイピング対象のサイトは下記のサイト。
ターゲットとする各株式のサイト構造を確認。
ここでは試しに、facebookのページをチェック。
ここで、アドレスをチェックすると、下記のようになっているのがわかる。
試しに、amazonのページもチェック。
https://stooq.com/q/?s=amzn.us
なるほど。「https://stooq.com/q/?s=~」に各株式のシンボルを代入することで、各株価のページに飛べることがわかった。
次に各ページから価格を抽出したい。
今回、欲しいのは赤丸で囲ったこの部分
googleの検証機能を使い、LAST価格周辺をチェックすると下記のような
下記のようなHTMLタグになっている。
<span style="font-weight:bold" id="aq_amzn.us_c4">1689.1500</span>
念のため、appleのページの同じLAST価格周辺をチェックする。すると、下記のようになっていることがわかった。
<span style="font-weight:bold" id="aq_aapl.us_c2">242.21</span>
おや、シンボルがそのまま id になっていたら抽出しやすいのに、なんか前にaq_とついていたり、「_c2」や「_c4」が後ろにくっついているではないか。
株式によってここの数字が変動するのは厄介だな~
ここで正規表現を使用することにした。
ここでは、「aq_シンボル名_c」から始まるidを抽出すれば、c2やc4といった末尾が変動しても問題ないと考えた。
search = re.compile("^amzn.us_c")
soup.find_all(id=search)
実際に試してみると、下記のように抽出された。
[<span id="aq_amzn.us_c4">1704.7500</span>,
<span id="aq_amzn.us_cr">1732.2200</span>,
<span id="aq_amzn.us_ct">1645.7050</span>,
<span id="aq_amzn.us_c4|3" style="font-weight:bold">1704.7500</span>]
この中でほしいのは3番目の要素なので、[2]で抽出できる。
上記を踏まえて、他の株価でも適用できるように、下記のようにコードを変更。
code_list = ["amzn.us","aapl.us"]
for i in range(len(code_list)):
URL = "https://stooq.com/q/?s=" + code_list[i]
response = requests.get(URL)
soup = BeautifulSoup(response.text, 'html.parser')
idselect ="aq_"+ code_list[i]+"_c"
search = re.compile("^"+idselect)
price_pre = soup.find_all(id=search)
price = price_pre[-1].get_text()
# 結果を見るため
print(price)
下記のように結果が出れば成功。
1689.1500
242.21
ついでに、株価名も抽出することにした。
HTMLの要素を確認したところ、下記のようになっていた。
<font id="f18"> Amazon.com Inc (AMZN.US)</font>
まずは、id ="f18"で一つに絞れるか試してみる。
soup.find_all(id="f18")
すると、下記の3要素が出てきた。
[<span id="f18"><b>Quotes</b></span>,
<font id="f18"> Amazon.com Inc (AMZN.US)</font>,
<font id="f18"><span id="aq_amzn.us_c4">1689.1500</span></font>]
このうち、必要なのは真中の1番目の要素なので、
soup.find_all(id="f18")[1].get_text()
とすると、
'\xa0Amazon.com Inc (AMZN.US)'
と出力された。
おや、変な記号「'\xa0」 が出てきたぞ。
これは、ノンブレークスペースといって、スペースの箇所での自動的な改行(行の折り返し)を防ぐ特殊なスペースであるとのこと。
上手くstrip()で削れないかな~
soup.find_all(id="f18")[1].get_text().strip()
'Amazon.com Inc (AMZN.US)'
やった~。削れた。でも (AMZN.US)というシンボル名が邪魔だ。
1行が長くなってきたので、とりあえず変数に代入する。
pre_title = soup.find_all(id="f18")[1].get_text().strip()
よーし、pythonのテキスト操作の出番だ。
カッコの始まりまでの文字が必要だから、カッコの始まりの文字までのスライスをすれば良いはずだ。
ということで、"( "が何文字目かを調べる。
text_pre.find("(")
結果、「15」と出た。
これを変数に代入
sp = text_pre.find("(")
スライスをためしてみる。
text_pre[:sp]
'Amazon.com Inc '
最後に無駄な空白があるので、strip()しておく。
text_pre[:sp].strip()
'Amazon.com Inc'
成功。これをtitleという変数に代入する。
title = text_pre[:sp].strip()
これで、タイトルの抽出ができた。
上記を踏まえて、コードを下記のように修正。
code_list = ["amzn.us","aapl.us"]
for i in range(len(code_list)):
URL = "https://stooq.com/q/?s=" + code_list[i]
response = requests.get(URL)
soup = BeautifulSoup(response.text, 'html.parser')
idselect ="aq_"+ code_list[i]
search = re.compile("^"+idselect)
price_pre = soup.find_all(id=search)
price = price_pre[-1].get_text()
text_pre = soup.find_all(id="f18")[1].get_text().strip()
sp = soup.find_all(id="f18")[1].get_text().strip().find("(")
title = text_pre[:sp].strip()
print(title,price)
これで下記のように表示されれば、成功。
Amazon.com Inc 1689.1500
Apple Inc 242.21
つぎに、googleシートへの挿入などを想定し、
titleとpriceをそれぞれのリストにしておく。
title_list = []
price_list = []
for i in range(len(code_list)):
URL = "https://stooq.com/q/?s=" + code_list[i]
response = requests.get(URL)
soup = BeautifulSoup(response.text, 'html.parser')
idselect ="aq_"+ code_list[i]+"_c"
search = re.compile("^"+idselect)
price_pre = soup.find_all(id=search)
price = price_pre[0].get_text()
text_pre = soup.find_all(id="f18")[1].get_text().strip()
sp = soup.find_all(id="f18")[1].get_text().strip().find("(")
title = text_pre[:sp].strip()
title_list.append(title)
price_list.append(price)
print("タイトルリスト:",title_list)
print("プライスリスト:",price_list)
下記のように表示されれば、成功だ。
タイトルリスト: ['Amazon.com Inc', 'Apple Inc']
プライスリスト: ['1689.1500', '242.21']
次回は、googleシートと連携して、今回得た情報を代入できるようにしたい。