Google Colab (Python)で学ぶ、seleniumを使った簡易スクレイピング

## ターゲット層
何かを収集したい人。作業を自動化したいめんどくさがりやな人。
自動操作、スクレイピングに興味がある人。

## 記事を書く理由
最近、pythonを触っていなかったから。学生の頃、主にpythonで開発していたが、今年社会人になり触る機会が減ったため久しぶりに触ろうと思い、この記事を書こうと思った。なぜ、スクレイピングかというと、学生時代コロナ禍で学校の登下校の登録がGoogle formで提出する必要があった。それの自動化が印象深かったため、自動操作（Selenium, chromedriver）を含めたスクレイピングを書くことにした。

## 全体的な進め方
まずは環境について。簡易に試してもらいたいためGoogleが機械学習を学ぶために無料て提供されているGoogle Colaboratoryを使う。イメージとしてはJupyterのweb版みたいな感じ。Googleアカウントを持っていれば使用できる。
その後Yahoo!さんでスクレイピングをやっていく。

## 順序
1. Google Colab を開く　https://colab.research.google.com
1. yahooニュースのタイトルとリンクを取得（BeautifulSoupを使用）
1. yahooニュースのタイトル詳細と詳細を取得（selenium, chromedriverを使用）

## yahooニュースのタイトルとリンク取得
```python
# 日本語フォントインストール
!apt install fonts-ipafont-gothic

# Seleniumインストール
!pip install selenium

# chromedriverインストール
!apt update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin
```

```python
# ライブラリのインポート
from urllib.request import urlopen
from bs4 import BeautifulSoup

# 取得したい要素のcss selector
target_css_selector = '#tabpanelTopics1 > div > div._2jjSS8r_I9Zd6O9NFJtDN- > ul > li > article > a'

# DOMの取得
data = urlopen("https://www.yahoo.co.jp/")
soup_parsed_data = BeautifulSoup(data, 'html.parser')

# 要素の取得
get_title_list = soup_parsed_data.select(target_css_selector)

for get_elem in get_title_list:
  get_title = get_elem.find('span').contents[0]
  get_link = get_elem.attrs['href']
  print(get_title)
  print(get_link)
```

## yahooニュースのタイトル詳細と詳細を取得
```python
# ライブラリのインポート
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# ブラウザをheadlessモード（バックグラウンドで動くモード）で立ち上げ
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)

def main():
  """
  yahooニュースのタイトル詳細と詳細を取得
  """

  # Yahooにアクセス
  url = "https://www.yahoo.co.jp/"
  driver.get(url)

  ## ここが少し危険（遷移が完了する前に下の処理が流れる可能性があるが、ここで落ちたことはない）

  # 記事の数を取得
  tag_title_list = driver.find_elements(by=By.CSS_SELECTOR, value="#tabpanelTopics1 > div > div._2jjSS8r_I9Zd6O9NFJtDN- > ul > li > article > a")
  title_length = len(tag_title_list)

  for index in range(title_length):

    # 個別に要素を取得
    title_css_selector = f"#tabpanelTopics1 > div > div._2jjSS8r_I9Zd6O9NFJtDN- > ul > li:nth-of-type({str(1+index)}) > article > a"
    tag_title = wait_get_element(title_css_selector)

    # ニュースページへ遷移
    tag_title.click()
    get_news_text(url)


def get_news_text(url):
  """
  ニュースページからニュース詳細ページへ遷移
  テキストの取得
  """

  # ニュース詳細ページへ遷移
  tags_2 = wait_get_element("#uamods-pickup > div.sc-muxYx.kNLljN > a")
  tags_2.click()

  # テキストの取得
  title = wait_get_element("#uamods > header > h1").text
  text = driver.find_elements(by=By.CSS_SELECTOR, value="#uamods > div.article_body.highLightSearchTarget > div > p")
  
  print('==============タイトル詳細')
  print(title)
  print('==============詳細')
  for text_line in text:
    print(text_line.text)

  # トップページに戻る
  driver.get(url)


def wait_get_element(css_selector):
  """
  要素が検出できるまで待機
  要素を取得
  """
  element = WebDriverWait(driver, 10).until(
  EC.presence_of_element_located((By.CSS_SELECTOR, css_selector))
  )
  return element

# 実行
main()
```
やっていることは、トップページでクリック、ニュースページでクリック、ニュース詳細ページで取得。
画面的には トップ⇨ニュース⇨ニュース詳細⇨トップ⇨ニュース⇨ニュース詳細⇨トップ...の繰り返し。



### 気づき
- getし直すと、WebElementオブジェクトが変わる。
```
<selenium.webdriver.remote.webelement.WebElement (session="aa3722e44bea11244055f625317e2b63", element="d7a9d819-e79c-414e-9312-1055145e2c46")>
<selenium.webdriver.remote.webelement.WebElement (session="aa3722e44bea11244055f625317e2b63", element="7a60957e-57c1-467b-9c07-dc23b5154db8")>
```

- このコードを書いている時、地震速報がきてエラーが出た。（速報系はテンプレが違うのかも）
- chromeからcss selectorをコピーした際、nth-childが入っている場合、nth-of-typeに書き換える必要がある。
- [Yahoo!ファイナンス掲載情報の自動取得（スクレイピング）は禁止](https://support.yahoo-net.jp/PccFinance/s/article/H000011276#:~:text=%E3%81%94%E5%88%A9%E7%94%A8%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82-,Yahoo!,%E3%81%8B%E3%82%89%E7%A6%81%E6%AD%A2%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)

その他、気づき、指摘があればコメントください。

#### 参考資料
- 待機時間　https://www.teru2teru.com/python/selenium/do-not-time-sleep/#outline__2
- 開発環境準備 https://i-doctor.sakura.ne.jp/font/?p=46745
- Selenium https://www.seleniumqref.com/api/webdriver_gyaku.html
- nth-childとnth-of-type https://system.hot-maker.com/73/
- chromedriverダウンロード　https://chromedriver.chromium.org/downloads