GASでスクレイピングをやってみる

## ゴール

WEBページから `http://schema.org` のデータをスクレイピングで取得する

## http://schema.org とは

ホームページに記載されている、説明をDeepLで翻訳すると。

> Schema.org はインターネット、ウェブページ、電子メールメッセージ、その他の構造化データのためのスキーマを作成、維持、促進することを使命とする、共同的な、コミュニティ活動です。
> 
> Schema.orgの語彙は、RDFa、Microdata、JSON-LDを含む多くの異なるエンコーディングで使用することができます。これらの語彙はエンティティ、エンティティ間の関係、アクションをカバーし、十分に文書化された拡張モデルによって簡単に拡張することができます。1000万以上のサイトがSchema.orgを使用して、ウェブページや電子メールメッセージのマークアップを行っています。Google、Microsoft、Pinterest、Yandexなどの多くのアプリケーションがすでにこれらのボキャブラリーを使用しており、リッチで拡張性の高い体験を実現しています。
> 
> Google、Microsoft、Yahoo、Yandexによって設立されたSchema.orgのボキャブラリーは、public-schemaorg@w3.org メーリングリストやGitHubを通じて、オープンなコミュニティプロセスによって開発されています。

ざっくりした理解だと、検索時に出てくる、ページ本文以外のQAや要約情報を設定することのできる、表現方法です。

  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/4f8eb00d-95af-5f5a-14d3-0c4e14770d3f.png)

この例だと、`駐車場はありますか？` などは、ページのHTMLを見てみるとこんな感じで記載されています。

```html
<script type="application/ld+json">
{"mainEntity":[
{"name":"駐車場はありますか？","acceptedAnswer":{"text":"駐車場は下記をご確認ください。<br>あり　1泊3千円（15:00〜翌11:00）15分毎200円加算。 バイク1台1泊500円","@type":"Answer"},"@type":"Question"},
{"name":"アクセス情報を教えてください。","acceptedAnswer":{"text":"交通アクセスは下記をご確認ください。<br>東京メトロ　西葛西駅より徒歩にて約１分","@type":"Answer"},"@type":"Question"},
{"name":"チェックイン時間・チェックアウト時間を教えてください。","acceptedAnswer":{"text":"チェックイン15:00〜26:00、チェックアウト10:00となっております。<br>（宿泊プランによって異なる場合がございますので、詳細は各宿泊プランをご確認ください。）","@type":"Answer"},"@type":"Question"}],"@context":"https://schema.org","@type":"FAQPage"}
</script>
```

## GASでスクレイピングする方法
ここから本題です。以下の３ステップで説明します。

1. Parserを読み込む
2. UrlFetchを利用してページを取得する
3. domをparseしてデータを抽出する

### 1. Parserを読み込む

こちらは、GASでスクレイピングするときに利用する王道のライブラリです。
https://script.google.com/home/projects/1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw/edit

この中に記載されている処理をそのままGASに転記して利用することも可能ですし、ライブラリ読み込みして利用することも可能です。

今回は、ライブラリを読み込みしてみます。

スクリプトID
`1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw` 

  - GASを開いて、ライブラリ横にある＋から、上記のスクリプトIDで検索
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/a5685a18-43bd-7721-4fbe-0080a6a38c8f.png)
  - 登録が完了すると、Parserがライブラリに登場します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/244e2bde-3a73-54c3-abd0-5b3c0ab24357.png)

### 2. UrlFetchを利用してページを取得する

UrlFetchApp.fetchを実行するだけで、ページ情報が取得できます。
めちゃくちゃ簡単です。
```js
function myFunction() {
  const response = UrlFetchApp.fetch('https://travel.rakuten.co.jp/HOTEL/165001/165001.html')
  console.log(response.getContentText())
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/e03f5e34-76c7-dc37-2788-5a5521daa93e.png)

### 3. domをparseしてデータを抽出する

１、２で準備したものを使って、あとは `type="application/ld+json` を取得すれば完了です。

`<script type="application/ld+json>`が基本系なのですが、 scriptタグの中にサイトによっては、その他のプロパティがついていることがあるので、 `type="application/ld+json">` だけで指定しています。

```js
function myFunction() {
  const response = UrlFetchApp.fetch('https://travel.rakuten.co.jp/HOTEL/165001/165001.html')
  const perseData = Parser.data(response.getContentText()).from('type="application/ld+json">').to('</script>').iterate()
  console.log(JSON.stringify(perseData.map(e => JSON.parse(e))))
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/99828d8e-8cb2-6d73-f387-3b710e1705d6.png)

## 最後に
これをスプレッドシートと組み合わせると、まとめてサイトの情報を抽出することができます。
どこかで使えるかもなので、頭の片隅にこんなことできるんだなー情報を持っておくのが良さそうです。