Pythonを使ってヤフーファイナンス情報を取得、スクレイピング

#複数企業コード対応版 企業コードから企業名と株価を取得する
#Anaconda JupyterLabによる動作 Shift+Enterで実行になる

動作環境:MacOS 、Python、Anaconda JupyterLab

面倒だった点は、複数タグが存在するタグ名tr,td,ddの扱い。複数の場合forで回して配列みたいにしてデータを取得する必要があるし、スペースが含まれるクラス名は別のプロパティ?で読み込む必要がある。

find_element_by_class_nameでスペースを含むクラス名はエラーとなるので、find_element_by_css_selectorとしてドット.で接続する。

誤り:el.find_element_by_class_name(‘stocksDtl clearFix’)

正:el.find_element_by_css_selector(“.stocksDtl.clearFix”)

以下はサンプルコード。使い方は、codelistに企業コードを入力すると、ヤフーファイナンスからスクレイピングして「コード、企業名、終値株価、前日比、日付」を半角スペース区切りで出力するだけ。ヤフーファイナンスに接続するときは、取得間隔を1,2秒程度空けている。連続で取得するとサーバ負荷が増えるから強制切断とかアクセスをブロックされてしまうかもしれない。

>>コード修正、Spanタグが存在しない時間帯があるみたいなので、存在するかどうかのチェックを追記した。2021年2月8日、12時06分

import time
from selenium import webdriver
import csv
import datetime
import os

codelist=[]
codelist=[6315,2207,6928,5724,2702]#企業コード、複数

def getName(code):
    # 仮想ブラウザ起動、URL先のサイトにアクセス
    driver = webdriver.Chrome('/usr/local/bin/chromedriver')#ここでエラーになったらパスが違うかchromedriverをインストールする
    #他のエラーで、「unexpectedly exited. Status code was:-9」だったら、Macの場合はシステム環境設定 → セキュリティとプライバシー で許可すればよい
    url='https://stocks.finance.yahoo.co.jp/stocks/detail/?code='
    driver.get(url+str(code)+'.T')
    #time.sleep(1)
    #title = driver.title
    #print(title)
    main = driver.find_element_by_id("main")
    el = main.find_element_by_id("stockinf")

    #エラー、nextClass = el.find_element_by_class_name('stocksDtl clearFix') Classにスペースが含まれるとエラーになるので別のメソッドにする
    nextClass = el.find_element_by_css_selector(".stocksDtl.clearFix")
    subNextClass = nextClass.find_element_by_class_name("forAddPortfolio")
    tableElem = subNextClass.find_element_by_class_name("stocksTable")
    dlElem = subNextClass.find_element_by_css_selector(".stocksInfo.clearFix")
    
    dds = dlElem.find_elements_by_tag_name("dd")
    trs = tableElem.find_element_by_tag_name("tr")
    symbol = trs.find_element_by_class_name("symbol")
    name = symbol.find_element_by_tag_name("h1")
    stockinfo = []
    stockinfo.append(str(code))
    stockinfo.append(name.text)
    tds = trs.find_elements_by_tag_name("td")
    
    for j in range(0,len(tds)):
        if tds[j].text != "":
            stockinfo.append(tds[j].text)

    ##ddタグの中に spanタグがあって、他に文字がある。spanタグのテキストだけが取得したかった。
    ##>>追記 2021年2月8日エラー処理を追加
    if len(dds[1].find_elements_by_tag_name("span"))>0:#存在チェック elementでなくてelementsにする
        stockinfo.append(dds[1].find_element_by_tag_name("span").text)#日付
    output=stockinfo
    driver.close()#起動したウィンドウを閉じる
    return output

###START
print("START#####################################")
tmpStr=""
f=0
for i in codelist:
    outputStr=getName(i)
    #コード、企業名、終値株価,前日比、日付
    for m in outputStr:
        if f==2:
            tmpStr+=m+'円'+' '
        else:
            tmpStr+=m+' '
        f+=1
        #print(outputStr[0],outputStr[1],outputStr[2]+"円",outputStr[3],outputStr[4])
    print(tmpStr)
    tmpStr=""
    f=0
    time.sleep(2)
print("End#####################################")

 

更に修正した。メソッドをクラスにした。また始値、高値、安値を入れた。2021/02/12

#Python を使って#ヤフーファイナンス 情報を取得、#スクレイピング 
#複数企業コード対応版 企業コードから企業名と株価を取得する
#Anaconda JupyterLabによる動作 Shift+Enterで実行になる
#修正、クラスに変更
#修正2021/02/12、始値、高値、安値を入れた

#手作業はcodelistにコードを入れる
import time
from selenium import webdriver
import csv
import datetime
import os

codelist=[]
codelist=[6134,7952,6462
         ]#企業コード、複数
#これからは、どんなに小さなプログラムでもクラスを使用する。そのほうが汎用性がある。
#同じメソッド名でもクラス名が異なればコピペして使用できる
class yahooFinanceClass():
        def __init__(self):
            self.hello="yahoo Finace"
        
        def getName(self,code):
            # 仮想ブラウザ起動、URL先のサイトにアクセス
            driver = webdriver.Chrome('/usr/local/bin/chromedriver')#ここでエラーになったらパスが違うかchromedriverをインストールする
            #他のエラーで、「unexpectedly exited. Status code was:-9」だったら、Macの場合はシステム環境設定 → セキュリティとプライバシー で許可すればよい
            url='https://stocks.finance.yahoo.co.jp/stocks/detail/?code='
            driver.get(url+str(code)+'.T')
            time.sleep(1)
            #title = driver.title
            #print(title)
            main = driver.find_element_by_id("main")
            el = main.find_element_by_id("stockinf")

            #エラー、nextClass = el.find_element_by_class_name('stocksDtl clearFix') Classにスペースが含まれるとエラーになるので別のメソッドにする
            nextClass = el.find_element_by_css_selector(".stocksDtl.clearFix")
            subNextClass = nextClass.find_element_by_class_name("forAddPortfolio")
            tableElem = subNextClass.find_element_by_class_name("stocksTable")
            dlElem = subNextClass.find_element_by_css_selector(".stocksInfo.clearFix")

            dds = dlElem.find_elements_by_tag_name("dd")
            trs = tableElem.find_element_by_tag_name("tr")
            symbol = trs.find_element_by_class_name("symbol")
            name = symbol.find_element_by_tag_name("h1")
            stockinfo = []
            stockinfo.append(str(code))
            stockinfo.append(name.text)
            tds = trs.find_elements_by_tag_name("td")

            for j in range(0,len(tds)):
                if tds[j].text != "":
                    stockinfo.append(tds[j].text)

            ##始値、高値、安値を取得
            detail = main.find_element_by_id("detail")
            innerDate = detail.find_element_by_class_name("innerDate")
            innerDate_divs = innerDate.find_elements_by_css_selector(".lineFi.clearfix")#S複数
            for n in range(0,len(innerDate_divs)):
                if len(innerDate_divs[n].find_elements_by_class_name("tseDtl"))>0:#存在確認は複数形
                    tseDtl = innerDate_divs[n].find_element_by_class_name("tseDtl")#こっちは単数
                    kubun=tseDtl.find_element_by_class_name("title").text
                    #共通の処理をまとめた
                    if kubun=="安値" or kubun=="高値" or kubun=="始値":
                        ymuiEditLink=tseDtl.find_element_by_css_selector(".ymuiEditLink.mar0")
                        kabuka=ymuiEditLink.find_element_by_tag_name("strong").text
                    #配列に追加    
                    if kubun=="安値":
                        stockinfo.append("安値:"+kabuka)
                    elif kubun=="高値":
                        stockinfo.append("高値:"+kabuka)
                    elif kubun=="始値":  
                        stockinfo.append("始値:"+kabuka)
                              
            ##ddタグの中に spanタグがあって、他に文字がある。spanタグのテキストだけが取得したかった。
            ##>>追記 2021年2月8日エラー処理を追加
            if len(dds[1].find_elements_by_tag_name("span"))>0:#存在チェック elementでなくてelements(複数S)にする
                stockinfo.append(dds[1].find_element_by_tag_name("span").text)#日付 こっちは単数のelement  
            output=stockinfo
            driver.close()#起動したウィンドウを閉じる
            return output
        
###START
print("START#####################################")
tmpStr=""
f=0
obj=yahooFinanceClass()
for i in codelist:
    outputStr=obj.getName(i)
    #コード、企業名、終値株価,前日比、日付
    for m in outputStr:
        if f==2:
            tmpStr+=m+'円'+' '
        else:
            tmpStr+=m+' '
        f+=1
        #print(outputStr[0],outputStr[1],outputStr[2]+"円",outputStr[3],outputStr[4])
    print(tmpStr)
    tmpStr=""
    f=0
    time.sleep(2)
print("End#####################################")    
'''出力例
START#####################################
6134 (株)FUJI 2,795円 前日比+51(+1.86%) 始値:2,794 高値:2,832 安値:2,777 14:08 
7952 (株)河合楽器製作所 3,510円 前日比+380(+12.14%) 始値:3,200 高値:3,540 安値:3,155 14:06 
6462 (株)リケン 2,400円 前日比+114(+4.99%) 始値:2,449 高値:2,449 安値:2,329 14:07 
End#####################################  
'''

 

こちらの記事もどうぞ