GASでスクレイピングをはじめよう！

# はじめに
当記事はGASでスクレイピングを始めるための手順を記します。
サンプルコードとして、Yahoo!ニュースのトップニュースからニュースタイトルを取得し、スプレッドシートに書き出す方法を記します。
初心者の記事ですので間違え等あればご指摘していただけると幸いです。

# GASでスクレイピングするメリット
GASでスクレイピングをするメリットとしては以下のものがあります。
　1. 環境構築がほとんど必要ない。
　2. 定期的にスクレイピングしたい場合、サーバーに置く必要がなく、GASの機能で実施することができる。
　3. スプレッドシートとの連携が楽。
他にもあるかもしれませんが、私が考える主なメリットは上記の通りです。

# GASの始め方
今回はスプレッドシートに書き込む処理があるので、最初にスプレッドシートを開きます。
1. Googleのトップ画面の右上の資格が並んだアイコンをタップし、スプレッドシートを選択します。
![gas1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/21296909-f5e2-dab6-d515-903f8694e741.png)
2. 新しいスプレッドシートを作成から空白を選択します。
![gas2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/7213ac7c-a060-5d57-1517-9488bd892a61.png)
3. 新規スプレッドシートが作成されました。
![gas3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/4b2bf680-9cc0-4ed1-21ea-ede86f14830f.png)
4. ツール > スクリプト エディタを押下します。
![gas4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/4549d7bc-e1eb-6bbd-251e-a2a94037377e.png)
この時以下の画面が表示される場合、ログイン中のGoogleアカウントを確認してください。
デフォルトアカウント以外の場合以下の画面が表示されます。
![gas5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/f4480824-4ad7-e827-5618-3b152d50ec76.png)
5. 以下のような画面が出ればGASを始める準備ができました。
![スクリーンショット 2021-03-14 19.15.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/3cbca83c-7b31-f642-c436-b1a76ddf0603.png)
6. GASでHello GAS!をコンソールログに出力してみましょう。
以下のコードを入力し、保存し、実行ボタン押下してみましょう。

```JavaScript:GAS
function myFunction() {
  Logger.log("Hello GAS!")
}
```

```console:実行ログ
19:27:06	お知らせ	実行開始
19:27:06	情報	Hello GAS!
19:27:07	お知らせ	実行完了
```
コンソールにログが出ますね！

# GASでスクレイピングする
今回はYahoo!ニュースのトップニュースのタイトルを取得します。
## Parserライブラリをインストールする
スクレイピングを行うにあたりHTMLをパースしてくれるライブラリとして、Parserライブラリをインストールします。
1. ライブラリを追加を押下します。
![スクリーンショット 2021-02-26 23.54.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/3244a542-835d-ac1c-0783-69de39631b35.png)
2. スクリプトIDに以下のIDを入力し、検索ボタンを押下します。
　``1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw``
![スクリーンショット 2021-02-26 23.54.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/5d5857ce-3bf0-82d3-af0c-5f843d06b8c6.png)
3. バージョンを選択し（今回は最新のバージョンの8を選択）、追加ボタンを押下します。
![スクリーンショット 2021-02-26 23.55.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/ee62ef8f-f32c-07a0-e270-9a2ea03a3603.png)
4. ライブラリのところにParserが登録されればOKです。
![スクリーンショット 2021-03-14 20.51.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/c21b9094-d04e-7960-c920-12440fb9b232.png)

## スクレイピングする
まずはコンソールログに出力するコードを書いていきます。

```javascript:GAS
function myFunction() {
  // URLを取得しHTMLを取得
  const url = "https://www.yahoo.co.jp/";
  var html = UrlFetchApp.fetch(url).getContentText('UTF-8'); //[1]

  // パースする
  var newsList = Parser.data(html)  //[2]
                  .from('3cl937Zpn1ce8mDKd5kp7u')
                  .to('</span>')
                  .iterate();

  // ニュースを出力する
  for(let i = 0; i < newsList.length; i++){
    Logger.log(newsList[i].replace(/.*>/,"")) //[3]
  }
}
```

`[1]` URLを設定し、HTMLを取得しています。
`[2]` 取得したHTMLから必要な部分を切り取っています。取得方法は後ほど解説。
`[3]` 整形してログに出力しています。

```console:実行結果
21:44:03	お知らせ	実行開始
21:44:03	情報	特防交付金 ずさんな事業評価
21:44:03	情報	米 アジア系への憎悪犯罪再燃
21:44:03	情報	火球 隕石となり海に落下か
21:44:03	情報	ソファ飛来あわや事故 注意を
21:44:03	情報	鼻綿棒で17回PCR 戸惑う取材
21:44:03	情報	推し卒業で有休OK 企業に反響
21:44:03	情報	ベッキー 第2子妊娠を発表
21:44:03	情報	アイヌ表現巡り 脳みそ夫謝罪
21:44:04	お知らせ	実行完了
```
きちんと取得できていますね！

### パースについて
取得したHTMLから必要な部分のみを抽出する処理を行います。
1. `GoogleChrome`で取得したいページを開きます。
2. `F12`キーを押下して`DevTools`を開きます。
3. 左上の`Select an element in the page to inspect it`ボタンを押下します。
![スクリーンショット 2021-03-14 21.57.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/d29788aa-f014-e4a3-fcd2-5a5714dd9f00.png)
4. トップニュースを押下すると該当のhtml部分が表示されます。
5. その前後でトップニュースのタイトル部分のみに共通している部分を探します。
![スクリーンショット 2021-03-14 22.01.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/11f820c0-1a20-5ca0-5811-72320240245e.png)
今回は`<h1 class="_3cl937Zpn1ce8mDKd5kp7u">`から`</span>`までがトップニュースタイトルで共通かつ他にはないコードになっています。
タイトル直前の`<span class="fQMqQTGJTbIMxjQwZA2zk _3tGRl6x9iIWRiFTkKl3kcR">` 部分は他の箇所にも使われているので採用できません。
6. 共通部分を見つけたのでコードに起こしていきます。

```JavaScript:GAS
  var newsList = Parser.data(html)
                  .from('3cl937Zpn1ce8mDKd5kp7u')
                  .to('</span>')
                  .iterate();
```
`.from()`に起点となる文字列を記入
 `.to()`に終了点となる文字列を記入
`.iterate()`で複数取得する

他にも様々な取得方法があるので[こちら様のサイト](https://www.kotanin0.work/entry/2019/01/06/200000)が非常に参考になります。

### データの整形について
Parserで取得しただけの状態では余計な文字列が残っているのでreplaceで整形します。

```JavaScript:GAS
newsList[i].replace(/.*>/,"")
```
`/.*>/`正規表現で`>`より前の文字を削除しています。

## スプレッドシートに書き込む
取得したタイトルをスプレッドシートに書き込む処理を追記していきます。

```JavaScript:GAS
function myFunction() {
  // シートを取得
  const sheet = SpreadsheetApp.getActiveSheet();
  // 最終行を取得
  const lastRow = sheet.getLastRow();

  // URLを取得しHTMLを取得
  const url = "https://www.yahoo.co.jp/";
  var html = UrlFetchApp.fetch(url).getContentText('UTF-8');

  // パースする
  var newsList = Parser.data(html)
                  .from('3cl937Zpn1ce8mDKd5kp7u')
                  .to('</span>')
                  .iterate();

  // 日付を書き込む
  sheet.getRange(lastRow + 1, 1).setValue(new Date());

  // ニュースを書き込む
  for(let i = 0; i < newsList.length; i++){
    Logger.log(newsList[i].replace(/.*>/,""))
    sheet.getRange(lastRow + 1, i + 2).setValue(newsList[i].replace(/.*>/,""));
  }
}
```
いつ取得したかも分かるように日付も書き込むようにしました。

**結果**
![スクリーンショット 2021-03-14 22.18.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/e0dd6b30-17a1-1d83-74e5-e220f1aa17f8.png)
きちんと書き込まれましたね。

# スクレイピングを定期的に自動実行する
このままだとただタイトルを取得するだけのコードなのでこれを定期的に自動実行するようにします。
1. トリガーを押下します。
![スクリーンショット 2021-03-14 22.22.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/0920f2f4-9d2f-15ab-4567-3599b495ae18.png)
2. トリガーを追加を押下します。
![スクリーンショット 2021-03-14 22.23.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/9a8e1fe5-cbb5-de5f-b277-cb06121c1ace.png)
3. トリガーを設定します。今回はそこまで更新頻度も高くないことが予想されるので、30分ごとに設定しました。
![スクリーンショット 2021-03-14 22.25.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/0a7a695c-379e-5093-907a-8cfb16480e78.png)
4. あとは30分待ちます。
![スクリーンショット 2021-03-14 23.06.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/bef52e15-7f4a-82f1-56e5-d465bd1f44c8.png)
実行されましたね！
結果も見てみます。
![スクリーンショット 2021-03-14 23.07.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547651/9ea180ba-8a22-8c5d-0d57-7376df285798.png)
きちんと書き込みされてますね！