Googleマップの検索結果をCSV出力したい（Chrome拡張機能）

※ 2024/10/27 BOM 付きじゃないとExcelで開けないので修正しました。

職場で、こんなことがありました。

社長：Google マップで検索したときの左側に表示される一覧をファイルに出力したいんだけど、そういうことできる？
自分：やったことないので分からないですけど、Google Apps Script っていうのがあるのでそれを使えばスプレッドシートに出力とかできるかもしれませんね🤔
自分：でも調べたこともないので、勘ですけど
社長：そうなんだ、じゃあできるって回答しておくね～
自分：おそらく、でお願いします！（誰かに聞かれたのかな）

社長：〇〇さん（お客さん）、これから来るって
自分：分かりました（やりたいことを説明しに来るのかな）

〇〇：Google マップのこの検索結果なんだけど、出力して
自分：え！？ できるかもしれないってだけで、まだ調べてもいないので今すぐは無理っす！
〇〇：ちょっと調べてみてよ～
自分：（ちょっと調べた結果）ちょっと思ってた方法は無理っぽいので、調べておきますね・・・
〇〇：じゃあ次回だね
自分：え、もしかして最短でほしい、って言ってます？
〇〇：土日あるから何とかなるでしょ～
自分：（ああ、僕の週末は・・・）

という経緯で、調べる羽目になりました。

# どういうやり方があるか調べる

今はだいぶいい時代になったので、自分が思ってたやり方以外にもいろいろと AI に提案してもらえます。
なので、早速パプってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179043/6da251ff-34db-dfd6-bcfb-9fda068d34ab.png)

まあよく分からないのでもう一度質問します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179043/ec825864-b309-8c1e-2460-9dbdefdfbf5f.png)

前にどういう風に質問したのか覚えてないのですが、その時は Chrome 拡張機能の「Google Maps Scraper」をお勧めされました。
ちなみにこれ以外にも Google Cloud の Places API というものも紹介されましたが、これは Google Cloud のアカウントが必要であり、課金が発生する可能性もあったので、簡単そうではなかったので除外。
というわけで、一番手軽そうな Chrome 拡張機能を使ってみることにしました。

# とはいえ Chrome 拡張機能なんて作ったことない

作ったことがないので、作り方も分かりません。
でも、今は AI の補助を受けられるいい時代になったので、 Cursor エディタを使って質問しながら作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179043/a91af3f2-61ae-d75e-6407-a1227eef2d97.png)

これはこの記事を書きながら実行してみた例ですが、まあこんな感じで質問しつつ、動かないところを直していきました。

# そしてできた

アルファベット順にファイルを紹介します。

```js:background.js
chrome.action.onClicked.addListener((tab) => {
    if (tab.url.includes('https://www.google.co.jp/maps') || tab.url.includes('https://www.google.com/maps')) {
        chrome.action.setPopup({ tabId: tab.id, popup: 'popup.html' });
        chrome.action.openPopup();
    } else {
        chrome.action.setPopup({ tabId: tab.id, popup: '' });
    }
});
```

```json:manifest.json
{
    "manifest_version": 3,
    "name": "Googleマップ検索結果CSV出力",
    "version": "1.0",
    "description": "Googleマップの検索結果をCSVに出力する拡張機能",
    "permissions": ["activeTab", "scripting"],
    "host_permissions": [
        "https://www.google.co.jp/maps/*",
        "https://www.google.com/maps/*"
    ],
    "action": {
        "default_popup": "popup.html"
    },
    "background": {
        "service_worker": "background.js"
    }
}
```

```html:popup.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Google Maps CSV出力</title>
  <script src="popup.js"></script>
</head>
<body>
  <button id="export">CSV出力</button>
</body>
</html>
```

```js:popup.js
document.addEventListener('DOMContentLoaded', () => {
    document.getElementById('export').addEventListener('click', () => {
        chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
            chrome.scripting.executeScript({
                target: { tabId: tabs[0].id },
                function: extractAndDownload,
            });
        });
    });
});

function extractAndDownload() {
    const results = [];
    const elementBase = document.querySelector('div[aria-label*="検索結果"][role="feed"]');
    for (const element of elementBase.querySelectorAll('div:not([class]):not([jslog])')) {
        const anchor = element.querySelector('a');
        if (!anchor) {
            continue;
        }
        const name = anchor.getAttribute('aria-label');
        const address = anchor.href;
        results.push({ name, address });
    }
    const csvContent = '\uFEFF' + results.map((e) => `${e.name},${e.address}`).join('\n');

    const encodedUri = encodeURI('data:text/csv;charset=utf-8,' + csvContent);
    const link = document.createElement('a');
    link.setAttribute('href', encodedUri);
    link.setAttribute('download', 'google_maps_results.csv');
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}
```

これらファイルを一つのフォルダに格納し、そのフォルダを Chrome に読み込ませます。
頑張って GIF 画像を作ってみました。
GIF 画像を作るのが一番時間かかったかもしれない🤔

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179043/845ea6ad-d261-7fb1-d66c-d44bd0bd3e70.gif)

名称と Google マップの URL を CSV 出力するようになっています。

これでひとまず次の出社時に乗り切れるかな・・・

というわけで、土曜日だけで何とかなったので日曜日は自分の勉強に充てたいと思います😇

---

そして追記。
上記のコードは BOM 付きに直しましたが、そもそも Shift JIS がいい、ということもあるかと思います。
変換方法がうまくいかずだいぶ苦労しましたが、ようやくうまくいったので Shift JIS で CSV ダウンロードをする場合は以下を使用してください。

https://github.com/landwarrior/chrome_extensions/tree/shift_jis/output_map_search_result