ホーム自己紹介ブログ
NO.42
DATE2020. 02. 24

Google Apps Script で FetchAllとRedirctURL の組み合わせは悪い

Google Apps Script (以下、GAS)で、困ったことがあったので備忘録として残しておこうと思います。

やろうとしたこと

特定ハッシュタグにおける、ツイートに書いてあるリンクを集めようとしていました。 そのリンクは、特定のドメインのみでフィルタリングしたいとも思っていました。 これらを RESTful API として提供したかったので、手軽に作れる GAS で作ろうと考えていました。

取り組んでみたこと

Twitter に書くリンクは、全て短縮 URL になります。 そのため、短縮 URL にアクセスし、リダイレクト先の URL を取りに行く必要がありました。 GAS では、リクエストメソッドである fetch があります。その fetch のfollowRedirectsというオプションを false にし、responseHeader の location を取ることで、解決(リダイレクト先の URL 取得が)できます。

Class UrlFetchApp  |  Apps Script  |  Google for Developers
Learn how to use Apps Script Class UrlFetchApp. Fetch resources and communicate with other hosts over the Internet.
developers.google.com

また、1 リクエストだけをする fetch では、直列処理になってしまうため、大変遅いです。 複数リクエストが同時にできる featchAll を使うことで、並列処理ができ、パフォーマンスが良いです。 要するに次のようなコードで解決しようと考えていました。

FetchAllとRedirectURL
FetchAllとRedirectURL
let urlList: Array<string> = ["https://t.co/XXXX", "https://t.co/YYYY"];
const locationList: Array<string> = [];
while (true) {
  const requestList: Array<URLFetchRequest> = urlList.map((url: string) => {
    return {
      url: url,
      method: "get",
      followRedirects: false,
      muteHttpExceptions: true,
    };
  });
  const responseList: Array<HTTPResponse> = UrlFetchApp.fetchAll(requestList);
  urlList = [];
  responseList.forEach((response: HTTPResponse) => {
    const allHeaders: any = response.getAllHeaders();
    const location: string = allHeaders["Location"];
    if (location) {
      locationList.push(location);
      urlList.push(location);
    }
  });
  if (urlList.length === 0) {
    break;
  }
}
return locationList;

追記 (20200228)

Standard search API
developer.twitter.com

Twitter の API レスポンスに urls がありました。説明はありませんでしたが、Tweet に貼られたリンク(短縮 URL と、オリジナル URL)の情報が入るそうです。

"urls": [
          {
            "url": "https://t.co/Rbc9TF2s5X",
            "expanded_url": "https://twitter.com/i/web/status/1125490788736032770",
            "display_url": "twitter.com/i/web/status/1…",
            "indices": [
              117,
              140
            ]
          }
 ]

困ったこと

この手段だと、Location を 1 つ 1 つ辿っていくことになります。 そのため、リダイレクトを自動的に追う( followRedirects: true )よりも、処理コストが大きいです。まあ、そこは目を瞑ります。

次です。

Google App Script の UrlFetchApp の 例外ハンドリングについて
UrlFetchApp を使って、Http 通信を行うスクリプトを作っていたのですが、 Http Response 200 以外のコード が返る場合は、 例外がスローされており、どうハンドリングするべきか調べた結果を記載します。
www.monotalk.xyz

fetch や fetchAll は、muteHttpExceptions: true としたとしても、ExceptionError が発生してしまいます。 そうすると、例えば 1000 件の URL を fetchAll した場合、どれが成功で、どれが失敗で、どれが未実施か がわからないというところです。

FetchAllとRedirectURL (Error)
FetchAllとRedirectURL (Error)

Promise.allSettled が使えれば、解決できるのかなと思いますが、現状 Promise は使えません。

私が思う解決策としては、

  • fetchAll ではなく、fetch を使う
  • fetchAll でリクエストする件数をいくつかの塊に分ける。(一気にではなく、分ける)

最後に

そもそもなのですが、今回やろうとしたことって GAS の良さがないですよね。 GAS は、GSuites 連携を簡単にできるという良さがあります。

しかし、今回はちょっとしたクローラーを作りたいだけでした。もちろん、GAS でも作れると思いますが、いくつかを妥協しないといけなくなります。

もし、そこが妥協できないのであれば、別の手段を検討する必要があります。

教訓

  • 表面的
    • fetchAll するときは、リダイレクト先 URL を取得しない
  • 根本的
    • 目的に適したツールを選択する

ちなみに、このツールは、並列処理をシンプルにコーティングできる golang で書き直そうと考えています。

Google

シェアする

フォローする

次のページ

Mac で バ美肉 りたい! (Zoom + Gachikoe + 3Tene or Reality)

前のページ

GMailをGCalendarに登録するサービス rMinc を作ってみた

関連する記事

タグ「Google」の記事

1週間で完成!Spotifyタイアップ検索アプリを作った話(駆け出し9年目)

どうも、Web業界で働き始めて9年目の駆け出しエンジニア、silverbirderです。Spotifyで音楽を聴いていると「この曲、どこかで聞いたことがあるけど、何の主題歌だったかな?」と思うこと、ありませんか?特にドライブ中や作業中に、ふと気になることが多いですよね。 私もそんな経験があり、気になったその曲が主題歌だったアニメを見始めたことがきっかけで、「簡単にタイアップ情報(アニメやドラマなど)を調べられるアプリがあったら便利だな」と思い、このアプリを作ることにしました。

2024-09-24

サービス
AI
Google
成果物
ERNIE-ViLG を Google Colaboratory で動かしてみた

ERNIE-ViLG というのが、"二次元キャラ" に強いという記事を目にしました。実際に使ってみようと、次のページで試したんですが、レスポンスがイマイチでした。そこで、次の記事を参考にして、ERNIE-ViLG を Google Colaboratory で動かすようにしました。

2022-09-03

AI
Google
クローリング
Googleアカウント画像を返却するだけのAPIを作った

みなさん、ご自身のプロフィール画像ってどう管理していますか?例えば、zennのプロフィール画像って、更新していますか? 私は、プロフィール画像の更新は面倒なので、放置することが多いです。(GravatarみたいなSaaSが使えたら良いのに...)

2021-12-20

Google
バックエンド
成果物
← ブログ一覧へ