見出し画像

【初心者向け】seleniumでニュースをスクレイピング

いろいろなサイトのニュースを集めて自分用のボットを作りたいので、まずはニュースのデータ収集用のコードを作ってみました。
今回もGoogle Coraboratory で作っていきます。

【準備】ドライバーとseleniumなどをインストール

#Chromiumとseleniumをインストール
#「!」印ごとColaboratoryのコードセルに貼り付けます。
!apt-get update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin
!pip install selenium

#SeleniumとBeautifulSoupのライブラリをインポート
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup

# ブラウザをheadlessモード(バックグラウンドで動くモード)で立ち上げてwebsiteを表示、生成されたhtmlを取得し、BeautifulSoupで綺麗にする。
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver',options=options)
driver.implicitly_wait(10)

詳しい方法はこちら

目的ページからhtmlデータをスクレイピング

今回は第一生命経済研究所のhtmlデータを取得します。

url = 'https://www.dlri.co.jp/'
driver.get(url)
html = driver.page_source.encode('utf-8')
soup = BeautifulSoup(html, "html.parser")
# print(soup.prettify())

soup.prettify()で得られたhtmlデータを確認できます。

driver.quit()

今回はこのページのデータしか取らないので、忘れないうちにドライバーを終了させておきます。

得られたhtmlデータからBeautifulSoupを用いて目的の部分を確認する

トップページのニュースのデータを取り出したいので、検証でhtmlを確認します。(chromeなら右クリック→検証で対象部分のhtmlを表示できます)

トップニュースはlistというclassを持つdivタグに囲まれていることがわかります。
soupからdivタグのclass 'list'を持つものを抽出します。

# divタグのclass'list'を持つものを抽出
news_list = soup.find_all("div", class_="list")

news_listに検索データが代入されています。
ここで、代数のtypeを確認してみましょう。

print(type(soup))
print(type(news_list))
print(len(news_list)) # divタグのclass'list'を持つグループがいくつあるか
print(type(news_list[0]))

これを実行すると以下のように出力されます。

"""
<class 'bs4.BeautifulSoup'>
<class 'bs4.element.ResultSet'>
3
<class 'bs4.element.Tag'>
"""

まず、'soup'はBeautifulSoupのオブジェクトです。
'news_list' は'element.ResultSet'となっています。
 divタグのclass'list'を持つ要素が複数個あったためと思われます。
news_list に含まれる要素がいくつあるかlenで調べると、3つあることがわかりました。
news_list[0] のtypeを見てみるとelement.Tagとなっています。
つまりnews_list にはclass'list'を持つdiv のTagが3つ入っていることになります。

news_listの中身を確認してみましょう。
news_list[0]を見てみます。

新着レポート部分のhtmlのようです。
順に確認していくと、このようになっていました。

今回は新着レポートのデータを取っていきたいので、news_list[0]を使用していきます。

htmlデータからニュースの日付、タイトル、記事へのリンクを取得する

記事部分のhtmlを見てみると、タイトルはclass'cell-content'のdivタグに入っていることがわかります。
まずはタイトルのみのリストを作っていきます。

news_titles = [title.text for title in news_list[0]('div', class_='cell-content')]

テキスト部分を抜き出すには*.textを使いますが、for文を内包表記してリストにします。
news_titlesの中身を見てみます。

うまくタイトルを取得できたようです。数を確認すると、全部で100記事のようです。
同様に日付も抽出してリストにします。

news_dates = [date.text for date in news_list[0]('p', class_='date')]

記事へのリンクも抽出します。

news_htmls = [news_html.get('href') for news_html in news_list[0]('a')]

'a'タグからhref部分を抽出しようとしましたが、Noneが入っています。hrefを持たない'a'タグ成分も拾ってしまっているようなので、Noneをリストから削除します。

# hrefにNanが含まれるので、Nanを削除
news_htmls_filtered = [x for x in news_htmls if x is not None]
news_htmls_filtered

これで、タイトル、日付、リンクのリストが作成できました。

得られたデータをデータフレームにまとめる

これらをデータフレームにまとめていきます。
(今回は直近20記事のみ使用)

import pandas as pd
df = pd.DataFrame(
    data={'date': news_dates[:20], 'topic': news_titles[:20], 'html': news_htmls_filtered[:20]})

良さそうですが、htmlが相対パスになっているので、絶対パスに変換します。

# htmlが相対パス表記なので、絶対パスに変換
df['html'] = url + df['html'].str[1:]

dfを確認してみます。

良さそうですね。
これで完成です!

最終的には、これを自動で定期的に取得し、LINE botとか作れたらいいなと考えてます。


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