機械学習SEの取り組みログ

pythonを使ったいろんな取り組み(kaggleだったり)を紹介していきます.

python スクレイピング

【2018年10月時点】産経ニュースから経済カテゴリのニュースの情報をスクレイピング【python】

投稿日:2019年11月4日 更新日:

スクリプトの目的・概要

タイトルの通り,
産経ニュース様から経済カテゴリのニュース情報をスクレイピングするスクリプトを書きました.
株価の時系列分析の補足情報として用いることを考えているため,

  • 記事タイトル
  • 記事内容
  • 公開日時
  • タイトルの先頭に存在する東証一部上場企業名
  • タイトルの先頭に存在する東証一部上場企業の株式コード

以上5点を抽出するスクリプトを開発しました.
これらを列名として,行ごとに1つのニュース情報が格納されたpandasのdataframeを出力するスクリプトです.

スクリプトの流れ

東証一部上場企業のコード&名称リストを作成

市場名を指定することで,その市場に上場している企業のコード一覧を返す関数get_code()を作成しました.jsmパッケージを用いています.
コードは以下の通りです.

def get_code(shijo="東証1部"):
    shijolist = []
    sappend = shijolist.append
    q = jsm.Quotes()
    for fieldcode in data:
        for BrandData in data[fieldcode]:
            if(BrandData.market == shijo):
                sappend(BrandData.ccode)
    return shijolist

 
コードと企業名をセットにしたdataframeを作成するため,カブサポ様の上場企業一覧csvを利用しました.
csvはこちらからダウンロードができます.
記事タイトルに企業名が含まれているかを調べるため,各企業名から(株)を外して利用しました.以下のような内容が格納されています.

銘柄コード 銘柄名 市場名 業種分類 単元株数 日経225採用銘柄
1301 極洋 東証1部 水産・農林業 100 NaN
1332 日本水産 東証1部 水産・農林業 100 1
1333 マルハニチロ 東証1部 水産・農林業 100 1
1352 ホウスイ 東証1部 卸売業 100 NaN
1376 カネコ種苗 東証1部 水産・農林業 100 NaN

一部上場企業のコードリストを引数に,csvから一部上場企業のデータだけを抽出する関数を書きました.コードは以下の通りです.

def complist(code):
    pd.read_csv("stock_list.csv",header = 0,engine = "python")
    compdata = compdata[compdata["銘柄コード"].isin(code)]
    return compdata

ニュース記事のスクレイピング

スクレイピングの流れは以下の通りです.

  • Beautifulsoupを用いて産経新聞の経済記事一覧のlxmlを取得する.
  • 得られたlxmlの中から,記事のタイトル,公開日時を取得
  • 各記事の見出しに含まれるリンクから記事の本文ページのlxmlを取得し,記事内容を取得する.

以下のgetscrape()関数によって,pandasの記事のタイトル,内容,公開日時が格納されたdataframeが作成されます.
引数のyearについてですが,記事の公開日時情報に年が含まれていないため用意しています.現在時刻などをとって年の情報を取得すればよいのですが…

def scrape(year="2018"):
    dflist = []
    pageSize = 1
    for i in range(1,pageSize+1):
        url = "https://www.sankei.com/economy/newslist/business-n" + str(i) + ".html"
        bshtml = gethtml(url)
        news = getnewses(bshtml,year)
        dflist.append(news)
    newsdata = dflist[0]
    for i in range(pageSize):
        newsdata = pd.concat([newsdata,dflist[i]])
    return newsdata

getscrape()関数で参照しているgethtml(url),getnewses(bshtml,year)について説明します.
まず,gethtml(url)に関してですが,これは引数のurlをスクレイピングして,Beautifulsoupを用いてlxmlデータを取得する関数です.
コードは以下の通りです.念のため,sleep関数で短時間に多くのアクセスをしないようにしてあります.

def gethtml(url): #urlのhtml形式を取得
    time.sleep(3)
    html = requests.get(url)
    bshtml =  bs4.BeautifulSoup(html.text,"lxml")
    return bshtml

続いてgetnewses(bshtml,year)関数について説明します.この関数を実行することで,gethtml関数で取得したlxmlの中から各記事のタイトル,記事内容および公開日時を抽出しています.コードは以下の通りです.

def getnewses(bshtml,year):
    newsdata = pd.DataFrame(index = [],columns = ["title","when","contents"])
    section = bshtml.find_all("div",class_= "entry_content")
    
    for elem1 in section:
            news = []
            a = elem1.select("a")
            
            test = a[0].get("href")
            contents_url = test
            contents = gethtml(contents_url)
            c_section = contents.find_all("div",class_="post_content")
            arts = c_section[0].find_all("p")
            
            tbody = ""
            for art in arts:
                if(art.string):
                    tbody += art.string
            span = elem1.find("div",class_ ="entry_meta")
            try:
                when_raw = str(span.select("time")[0].string)
                timelist = when_raw.split(" ")
                month,day = timelist[0].split(".")
                hour,minute = timelist[1].split(":")
                when = pd.datetime(int(year),int(month),int(day),int(hour))
            except:
                print("no time data")
                continue
                
            news.append(a[0].string)
            news.append(when)
            news.append(tbody)
            news = pd.Series(news,index = newsdata.columns)
            newsdata = newsdata.append(news,ignore_index = True)
    return newsdata

企業に関するニュースの抽出&企業の名称とコードの追加

企業名がタイトルに含まれるニュースデータを抽出して,その企業名と株式コードを新たな列項目として付加したdataframeを返す関数matchtitle(newsdata,compdata)を作成しました.
ここで,newsdata,compdataはそれぞれgetscrape()関数で抽出したニュースデータとget_code()関数で取得した企業データです.

def matchtitle(newsdata,compdata):
    """一部上場している企業一覧とタイトル一覧から,企業名が入っているタイトルを抽出"""
    selectnews =  pd.DataFrame(index = [],columns = ["title","when","contents","company","code"]) 
    for compname in compdata["銘柄名"]:
        for newsname in newsdata["title"]:
            if(compname == newsname[:len(compname)]):
                appenddata = newsdata[newsdata["title"] == newsname]
                appenddata["company"]  = compname
                appenddata["code"] = int(compdata.loc[compdata.loc[:,"銘柄名"] == compname,"銘柄コード"])
                selectnews = selectnews.append(appenddata,ignore_index = True)
 
    selectnews[["code"]] = selectnews[["code"]].astype(int)            
    return selectnews

なぜかニュースが重複して抽出されてしまうため,重複しているニュースを削除する関数を作りました.

def delete_duplicatedNews(newsdata):
    new_newsdata = pd.DataFrame(index = [],columns = newsdata.columns)
    for no_old,row_old in newsdata.iterrows():
        isAdd = True
        for no_new ,row_new in new_newsdata.iterrows():
            if(row_old["wakachi"] == row_new["wakachi"]):
                isAdd = False
        if(isAdd):
            new_newsdata = new_newsdata.append(row_old,ignore_index = True)
    return new_newsdata

抽出結果

以下のようなdataframeが抽出できます.

 

title when contents company code
カルビーが47都道府県の地元味ポテチ東京は「てんぷら味」 2018/10/25 16:00 カルビーは25日、江戸前天ぷらの味わいを再現した「ポテトチップス\u3000てんぷら味」を29日に、… カルビー 2229
日本ハムが早期退職200人募集社員の1割超 2018/10/31 19:00 日本ハムが31日発表した平成30年9月中間連結決算は、売上高が前年同期比1・4%減の618… 日本ハム 2282
キッコーマンの茂木友三郎名誉会長が文化功労者に 2018/10/26 16:00 平成30年の文化功労者に選ばれたキッコーマンの茂木友三郎名誉会長は26日、「日本の『食』に… キッコーマン 2801
キッコーマン、ライブ型レストランを東京・有楽町に新設 2018/10/25 13:00 キッコーマンは25日、有名シェフによる料理の実演などが楽しめるライブ型の新スタイルレストラ… キッコーマン 2801
東レのキャンペーンガールにタレントの松田紗和さん 2018/10/30 14:00 東レは30日、平成31年のキャンペーンガールに、タレントの松田紗和さん(20)を起用すると… 東レ 3402

今後の方針

文書データを時系列分析の補助情報として扱うためには,文書データを数値化する必要があります.文書を数値化する手法としては,細かい説明は割愛しますが,

  • Latent Semantic Analysis(LSA)
  • Latent Dirichlet Allocation(LDA)
  • Doc2Vec

といった手法があります.

どの手法を用いるにしても,文書を単語あるいは品詞ごとに区切る必要があります.英語の場合は空白ですでに区切られているため,あとは活用形を原形に戻すかどうか(ステミングと言います)などを考えればよいのですが,日本語の場合は適切な区切り位置で文を区切る必要があります.これを自動的に行うための解析手法は形態素解析と呼ばれ,すでに様々な形態素解析エンジンが開発されています.
今後の方針として,

  • 文書データを形態素解析エンジンを用いて分かち書きで表現
  • 得られた分かち書きデータを,Doc2Vecを用いて数値化する

といった形でデータの加工をやっていきます

-python, スクレイピング
-, ,

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

no image

【scikit-learn】Logistic回帰にLasso回帰の正則化項(ペナルティ項)を設定する方法【Python】

概要 (動機)Pythonのscikit-learnライブラリを用いてロジスティック回帰を実施する際,ラッソ回帰のように正則化項を設けて変数選択もしたいと思った. 調べたところ,scikit-lear …

no image

【自然言語処理】ニュース記事のベクトル表現と株価変動の関係性を可視化する【python】

本記事の概要 以前紹介したニュース記事をスクレイピングするスクリプトとニュース記事をベクトル化するスクリプトで得られたベクトルの各成分のうちどれかが,株価の変動との間に相関があるかどうか調べてみました …

no image

【kaggle】「SIIM-ISIC Melanoma Classification」コンペのデータを用いてEfficientNetとResNetの性能比較をしてみる

本記事の概要 kaggleで2020/07/07現在開催中のSIIM-ISIC Melanoma Classification(画像認識コンペ)に最近注力しています. 画像認識ど素人ですが,以下の2つ …

no image

【自然言語処理】得られたニュース記事をgensim, nattoライブラリを用いてベクトル化する【python】

記事の概要 この記事では,機械学習手法であるdoc2vecを用いてニュース記事を30次元のベクトルで表現した結果について紹介していきます. また記事をベクトル化する過程で,文を品詞ごとに区切る処理(形 …

no image

【TensorFlow 2.0】tfrecordファイルに格納されているデータの数を確認するコマンド【Python】

記事の概要 TensorFlow特有のデータ保存形式「tfrecord」で保存したデータセットについて,何件のデータがtfrecordに圧縮されているかを確認する方法を記載しました. 単純にlen(t …

プロフィール


sudot

某IT企業でデータ分析業務をしています.
日ごろの機械学習に関する取り組みを発信していきます.
最近kaggleのexpertになれました.いつかmasterになるのが夢.