Netlify Functions を使って Qiita のトレンド API を非公式で作ってみた


2022.02.12追記: 諸事情あり Netlify Functions から Vercel Serverless Functions に移行しました。
今後は h ttps://qiita-api.netlify.app ではなく https://qiita-api.vercel.app にアクセスしてください(念のため前のリンクからリダイレクトを飛ばすようにはしていますが...)。

Zenn 版はこちら


Qiita の API にはトレンド記事一覧を取得する API が無いので、作ったみたという話です。
早速試してみたい方は

h ttps://qiita-api.netlify.app/.netlify/functions/trend
https://qiita-api.vercel.app/api/trend

または

h ttps://qiita-api.netlify.app/trend.json
https://qiita-api.vercel.app/trend.json

を確認してみてください。
(万一上手く取得できていない場合はコメント欄かリポジトリの Issue にてお知らせください。)

背景

QiitaAPIにトレンドが見当たらないので泣いてたら という記事に経緯がありますが、かつてはトレンド記事一覧は https://qiita.com/trend.json を GET することで得られたものの、2019年12月現在は公式には API が提供されていません。
ただ、トップ画面の div タグに埋め込まれる形で JSON (の文字列)があり、これをスクレイピングすることで記事一覧を得ることができます。
 
わざわざスクレイピングするのは面倒だという気持ちになったので、直接 JSON を返せるような URL を自前で立てることにしました。

Netlify Functions

Netlify 上で AWS Lambda を使えるというものです。
無料だと Requests が 125,000/月, Runtime が 100 hours/月 (2019年12月現在)まで使えるので、趣味プロダクトなら全然余裕の範囲ですね。

どう使っているか

以下のような関数を書いています。Qiita の URL を axios で GET して、cheerio でパースしているだけなので、非常に単純ですね。

src/lambda/trend.ts
import axios from 'axios'
import cheerio from 'cheerio'

const fetchTrend = (html: string) => {
  const $ = cheerio.load(html)
  const raw = $('script[data-component-name=HomeIndexPage]').html() ?? ''
  if (raw === undefined) return {}
  const rawData = JSON.parse(raw).trend.trend.edges

  return rawData.map(obj => {
    // 不要なプロパティを削除
    delete obj.followingLikers
    delete obj.isLikedByViewer

    delete obj.node.isLikedByViewer
    delete obj.node.isStockableByViewer
    delete obj.node.isStockedByViewer
    delete obj.node.followingLikers
    delete obj.node.recentlyFollowingLikers

    return obj
  })
}

export const handler = async () => {
  const url = 'https://qiita.com/'

  return await axios
    .get(url)
    .then(({ data }) => {
      return {
        statusCode: 200,
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Content-Type': 'application/json; charset=utf-8'
        },
        body: JSON.stringify(fetchTrend(data)),
      }
    })
    .catch(err => {
      return {
        statusCode: 500,
        body: err,
      }
    })
}

Lambda 本体の実装の他は、基本的には netlify.toml.babelrc をいじるだけです。詳しくは


をご確認ください。

参考になるリンク