【Python】Google Colab上でメルカリ商品ページをWebスクレイピングした結果をGoogleスプレッドシートに保存して、商品の画像も表示させてみる

この記事は以前YouTubeに公開した下記の動画の内容を元にしています。

[【Python学習】メルカリ商品ページをWebスクレイピングした結果をGoogleスプレッドシートに保存して、商品の画像も表示させてみる](https://www.youtube.com/watch?v=wgFpW7nQFN4)

<font color="red">なお、この記事で扱っている内容はあくまで学習目的によるものとなります。
スクレイピングは場合によっては相手のサーバに対する負荷などにも繋がりますので、常識の範囲内で行うようにしてください。</font>

## Google Colab上で実行するPythonコード
まずは動画内で書かれている実際のコードを下に貼っていきます。

### gspreadのインストール

```bash
!pip install gspread
```

ついつい、癖で `gspread` を明示的にコマンド打ってインストールしていましたが、これは不要でした...
このやり方でインストールしても、元々Colabにインストールされているバージョンと変わらないので、正直意味がなかったです。

こちらの詳細については、以前投稿した下記の記事を参照ください。
 https://qiita.com/safa/items/bfa52430f920ac562bec#gspread%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

### GoogleスプレッドシートにColab上からアクセスできるようにするためのおまじない

```python
from google.colab import auth
from oauth2client.client import GoogleCredentials
import gspread

auth.authenticate_user()
gc = gspread.authorize(GoogleCredentials.get_application_default())
```

`Google Colab`上でGoogle スプレッドシートにアクセスするためのコードです。
半ば自分の中では `おなじない` と化しています。

こちらのコードを実行すると、URLが表示されます。
画面に従って操作していけば認証自体は問題なく完了するかと思います。
(あらかじめ自身のGoogleアカウントでログインしていると楽です)

## メルカリ商品ページをWebスクレイピングした結果をGoogleスプレッドシートに保存して、かつ商品の画像を表示させるためのコード

実際のPythonコードがこちらです。
保存先として指定するGoogleスプレッドシートURLを入力した上で実行してください。

```python
from bs4 import BeautifulSoup
import requests

workbook_url = "保存先となるGoogle SpreadsheetのURL"
workbook = gc.open_by_url(workbook_url)

mercari_url = "https://www.mercari.com"
fetch_path = "/jp/category/967/"

headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4222.0 Safari/537.36'}

# fetch_url: https://www.mercari.com/jp/category/967/
fetch_url = mercari_url + fetch_path

print("取得URL: " + fetch_url)

r = requests.get(fetch_url, headers=headers)

soup = BeautifulSoup(r.text, "lxml")

title = soup.find('title').get_text()

worksheet = workbook.add_worksheet(title=title, rows=100, cols=4)

item_list = soup.find_all("li", class_="sc-bwzfXH")

result_list = []

worksheet.append_row(["ID", "タイトル", "値段", "詳細URL", "画像"])

for i, item in enumerate(item_list):
  item_title = item.find("span").get_text()
  item_price = item.find("div", class_="style_thumbnail__N_xAi").get_text()
  item_url = mercari_url + item.find("a")["href"]
  image = "=IMAGE(\"" + item.find("img")["src"] + "\")"
  worksheet.append_row([i, item_title, item_price, item_url, image], value_input_option="USER_ENTERED")

print("完了！")
```

実行に成功すると、下記のようにGoogle スプレッドシート内に画像が表示された状態でデータが書き込まれます。

<img width="550" alt="実際にWebスクレイピングを実行した結果のGoogleスプレッドシート" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649550/af0a0652-2cc8-a9fd-b46f-f890763e3bc2.png">

## コードの補足説明

書いたコードに関する補足説明をいくつか行っていきます。

### User-Agentの付与
```python
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4222.0 Safari/537.36'}

・
・
・

r = requests.get(fetch_url, headers=headers)
```

メルカリのページでは、`User-Agent`がないアクセスに対しては`403`を返すようです。
requestsでは、`get`の第２引数にオプションとして `User-Agent`を設定することが可能なので、こちらを設定した上でアクセスを行っています。
なお、`User-Agent`の内容は動画作成時の `Google Chrome Canary` のものになります。
`Devtools`の`Network`タブ内にて表示されている値をそのまま使用しています。

### lxmlについて

```python
soup = BeautifulSoup(r.text, "lxml")
```

`Google Colab`上では最初から `lxml` がインストールされているため、いきなりこのようなコードを書いてもエラーにはなりません。
もしローカルで同じコードを実行する場合は、`lxml`も、pipインストールしておく必要があります。

### シートのタイトルについて

```python
title = soup.find('title').get_text()

worksheet = workbook.add_worksheet(title=title, rows=100, cols=4)
```

Pythonスクリプトを実行した際に、取得したページのタイトルをシート名にしてシートを作成するようにしています。
`add_worksheet`関数内で、作成するシートの縦横を指定していますが、指定しなくとも勝手に追加はされていくようでした。
(とりあえず１００行、４列で指定しています)

### GoogleスプレッドシートのIMAGE関数を用いて画像を表示させる

```python
  image = "=IMAGE(\"" + item.find("img")["src"] + "\")"
  worksheet.append_row([i, item_title, item_price, item_url, image], value_input_option="USER_ENTERED")
```

Google スプレッドシート内に画像を表示させる場合、Googleスプレッドシート側で提供しているIMAGE関数を用います。

[IMAGE - ドキュメント エディタ ヘルプ](https://support.google.com/docs/answer/3093333?hl=ja)

ドキュメントを見てみると、いくつかのオプションが提供されているようでしたが、今回は使用しませんでした。
本当は画像に合わせてセルのサイズを変更したかったのですが、残念ながらその機能は提供されていなかったので、画像URLだけを渡す形としています。

> 画像に合わせてセルのサイズを変更するモードはありません。

上のヘルプページより引用
(この機能が使いたかった...)

`gspread`の `append_row` 関数はそのまま画像URLを渡しても `'=IMAGE` となってしまい、文字列として解釈されてしまいます。
そのため `value_input_option="USER_ENTERED"` をoptionとして指定しています。

これを指定することで、Google スプレッドシート上でユーザが画面にその文字を打ち込んだときと同じ挙動をするようになります。
この場合だと `=IMAGE("・・・")` という値をユーザがそのまま打ち込んだとき同じように解釈されるため、スプレッドシート側は狙い通りに画像を表示してくれます。

■参照ドキュメント
[API Reference - gspread(append_row)](https://gspread.readthedocs.io/en/latest/api.html#gspread.models.Worksheet.append_row)
[ValueInputOption | Sheet API](https://developers.google.com/sheets/api/reference/rest/v4/ValueInputOption)

## 最後に(宣伝)
これで以上となります。


YouTubeに時折Python関連の動画をアップしています。
よろしければ覗いてみてください！

[サファのColabでPython学習](https://www.youtube.com/playlist?list=PLD32o2f8pwYNZkn1UrSd1PuoZ5WQSssVS)