見出し画像

ぽんずは日経先物・OPでなかなか勝てない②スクレイピング編

ぽんずです。
今晩のご飯は豚と白菜のミルフィーユ鍋にしようと思っています。
では、前回の記事に続き、スクレイピングの話をしていこうと思います。

スクレイピング

pythonは日頃から使っているので準備は楽でした。
今回使ったモジュールはこんな感じ

import datetime
import requests
from bs4 import BeautifulSoup
import pandas as pd

requestsとBeautifulSoupってのがスクレイピングに大事なやつです。

 # スクレイピングしたいURLを入力
def getsoup(URL):
    TARGET_URL = URL 
    html = requests.get(TARGET_URL)  # HTMLを取得
    soup = BeautifulSoup(html.content, "html.parser")  # HTMLを解析

    #複数のタグを取る findall メソッドを利用して、複数タグを取得します。
    gets=soup.find_all("a")
    #soup.a.get("href")のように指定することで、URLを取得することができる
    return gets[4].get("href")

んで、それらを使った関数作ります。
これはURLを取得するための関数なんですけど
イメージとしては、yahooニュースのURLを取得ような感じです。
returnで返してるのがたくさん表示されているURLの5番目を選択してそれだけ取得しています。

んで、なんでこんな面倒なことになっているかというと
毎日データとコメント2つ記事を書いてらっしゃる方だったので
データだけを取りたいということになります。
でも、データのある記事のURLは連番になっている訳ではなのでまーーー大変でした。
そこで、"http://…………/2024-02-01.html"このような日にち指定からデータ記事のURL取得を考えました。
日にちはfor文で回していけばいいので、下みたいな感じ。

# 開始日と終了日を設定
start_date = datetime.date(2024, 2, 14)
end_date = datetime.date(2024, 2, 15)

# 日付を1日ずつ進めながら出力
current_date = start_date
while current_date <= end_date:
    # 平日(営業日)の場合のみ出力
    if current_date.weekday() < 5:
        try:
            date=current_date.strftime("%Y%m%d")
            datename=getsoup(current_date)
            iv=getIV(datename,date)
            ivdf=pd.concat([ivdf,iv])

        except:
            pass
    current_date += datetime.timedelta(days=1)

何日から何日のデータを取得ってできるの便利だよね~
土日は飛ばして、データがない日はpassしちゃう。
ivを取得してivdfのデータフレームに格納する流れ。

def getIV(date,date2):
    TARGET_URL = date
    html = requests.get(TARGET_URL) 
    soup = BeautifulSoup(html.content, "html.parser") 
    #今回は"tbody"の中の"td"にデータがあった
    con = soup.find("tbody").find_all("td")

    #findとfindallでは出力形式が違う
    #find → bs4.element.Tag
    #find_all → bs4.element.ResultSet
    #ResultSetはTagの集合体
    #てことで、全部分けてlistに入れる
    room=[]
    for i in con:
        room.append(i.text)

    #前102個のデータ削除
    del room[:102]

    #l=list名、cols=列数(分割したい数)
    #convert関数を使って一次元listを二次元listに変換
    def convert_1d_to_2d(l, cols):
        return [l[i:i + cols] for i in range(0, len(l), cols)]

    pp=convert_1d_to_2d(room,7)

    # DataFrameを作成
    df = pd.DataFrame(pp)
    df.columns = df.iloc[0]
    df = df.drop(df.index[0])
    return df

最後にデータがあるURLからデータだけを抜き出すための関数。
ここめっちゃ大変だったぁ
まずは4行目のこのコード
soup = BeautifulSoup(html.content, "html.parser")
これでsoupの中にhtml情報を全部突っ込みます。

次に上から6行目のこのコード
con = soup.find("tbody").find_all("td")
htmlの中に使ってある"tbody"の中の"td"を全部ちょうだいって言います。

.findだと一番初めの"tbody"を1個だけ
.find_allだと"td"全部取得します。

この時に嫌なことが、それぞれ取得するデータは型が違うってことなんです。このことについては少し後で話します。
まずは"tbody"とかどうやったらわかるかって話から。
PCだとF12を押すとhtml情報が出てきます。

まずは赤丸のとこ。(へったくそな丸だな)
そこクリックして、ホームページ上の青矢印をクリックすると
黄色矢印のようにhtmlのどこに書いてあるか教えてくれます。

んでんで、そこを上に遡っていくと
tbodyに書かれていることがわかるっていう話。
どう?やれそう?思ったより簡単だったでしょ?


では、少し戻ります。
.findだと一番初めの"tbody"を1個だけ
.find_allだと"td"全部取得します。
のデータの型が違うって話です。
1個取得するときは、html文1行(さっきの画像でいう右の1行)
全部取得するときはhtml文複数を1行として渡されます。
#find → bs4.element.Tag
#find_all → bs4.element.ResultSet
正確な型の名前は上になります。

ちょっとめんどくさいところはpython上でどうにかやりました。

こんな感じでデータが欲しい日を決めて
データ取得しました。

最終的に取れたデータ

こんな感じ。


今回のオチ

コードの説明なんか初めて書いたからなかなか人に伝わらなさそう。。。
てか、目次がない。見にくい。笑
あと、コード全文を公開する気はあんまないです。
どうしてもって人は声をかけてもらえると。

まあ、データとれたぐらいで満足しちゃだめなんだけどね。
勝てるようにならないと。まずは検証。

ではまた。

この記事が気に入ったらサポートをしてみませんか?