米国株価を泥臭くスクレイピングする


スクレイピング対象のサイトは下記のサイト。

https://stooq.com/

ターゲットとする各株式のサイト構造を確認。

ここでは試しに、facebookのページをチェック。

ここで、アドレスをチェックすると、下記のようになっているのがわかる。

https://stooq.com/q/?s=fb.us

試しに、amazonのページもチェック。

https://stooq.com/q/?s=amzn.us

なるほど。「https://stooq.com/q/?s=~」に各株式のシンボルを代入することで、各株価のページに飛べることがわかった。

次に各ページから価格を抽出したい。

今回、欲しいのは赤丸で囲ったこの部分

コメント 2020-03-17 194401

googleの検証機能を使い、LAST価格周辺をチェックすると下記のような

コメント 2020-03-17 194736


下記のような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

ついでに、株価名も抽出することにした。

コメント 2020-03-17 194917

HTMLの要素を確認したところ、下記のようになっていた。

<font id="f18">&nbsp;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シートと連携して、今回得た情報を代入できるようにしたい。


いいなと思ったら応援しよう!