👾
ディズニーのグッズ情報をNext.jsのAPI Routesで取得してみる
このページでは、Next.jsのAPI routesを使用して、サーバーサイドでWEBスクレイピングをしてみました。
とりあえずurlからhtmlを取得してみる
/api/scraping/goods で欲しい情報をjsonで返すようにしてみます。
まず、簡単にディズニーリゾートのグッズ情報のテキストを取得するコードを調べて書いてみました。
route.ts
import { NextResponse } from 'next/server';
export const GET = async () => {
const fetchUrl = 'https://www.tokyodisneyresort.jp/goods/116001582/';
const response = await fetch(fetchUrl, {
method: 'GET',
});
if (!response.ok) {
return NextResponse.json({
message: 'Failed to fetch data from the URL.',
});
}
const data = await response.text();
return NextResponse.json({
message: 'GET method is not allowed for this endpoint.',
data,
});
};
はい。なんとこれだけ。調べててfetchで取得できることを知らなかったので簡単でびっくりしました。
(当たり前かもしれないけど、許して)
取得できたデータ(一部だけ)
"html": "<!DOCTYPE html>\n<html lang=\"ja\">\n<head>\n<meta charset=\"UTF-8\">\n\n<link rel=\"shortcut icon\" href=\"/_public/favicon.ico?dummy=1518591858\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/css/goods.css\" charset=\"UTF-8\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/publis.css\" /><meta name=\"viewport\" content=\"width=device-width, minimum-scale=1, maximum-scale=1\" /><meta name=\"keywords\" content...
特定の要素を抽出してみる
ただ、このままだとただの文字列として返されてしまって、特定の要素を抽出するにはとても面倒なので"cheerio"というライブラリを使用します。
まずはインストール〜
yarn add cheerio
とりあえず、商品名を取得してみたいので先ほどのroute.tsを以下のように編集します
route.ts
+import * as cheerio from 'cheerio';
import { NextResponse } from 'next/server';
export const GET = async () => {
//htmlを取得する
const fetchUrl = 'https://www.tokyodisneyresort.jp/goods/116001582/';
const response = await fetch(fetchUrl, {
method: 'GET',
});
if (!response.ok) {
return NextResponse.json({
message: 'Failed to fetch data from the URL.',
});
}
//変数名がわかりづらかったので変更
- const data = await response.text();
+ const html = await response.text();
+ const $ = cheerio.load(html);
// ここで欲しい要素を取得(クラス名やタグは実際のHTMLに応じて変えてください)
+const itemName = $('.heading1').text().trim();
return NextResponse.json({
message: 'GET method is not allowed for this endpoint.',
- data,
+ itemName,
});
};
結果
{
"message": "GET method is not allowed for this endpoint.",
"itemName": "ぬいぐるみコスチュームNEW"
}
無事取得できました。
結構簡単に取得、抽出ができました。
Vercelにデプロイ
Vercelにデプロイしてapiの動作を確認しようとアクセスしてみると、タイムアウトエラーが出てしまいました。色々調べてみたらNode.jsの時間制限に引っかかってるっぽいので、Edge Functionsを使用することにしました。
route.ts
export const runtime = 'edge';
route.tsの一番上に↑を追加して終わり。
無事タイムアウトにならず処理することができました。
終わり
ローカルだと動いて、Vercelだとタイムアウトする理由を特定するのと、それを修正するのに時間がかかってしまいましたが、学べたので良しですね。
もっといい方法があったら教えてください!
Discussion