import express from "express";
import fetch from "node-fetch";
import { JSDOM } from "jsdom";
import cors from "cors";
const app = express();
app.use(express.json());
app.use(cors());
// 単一URLからTitleを取得
async function fetchTitle(url) {
try {
const res = await fetch(url, { timeout: 8000});
const html = await res.text();
const dom = new JSDOM(html);
const title = dom.window.document.querySelector("title")?.textContent || "";
return { url, title };
} catch (err) {
console.error("タイトル取得エラー", err.message);
return { url, title: null, error: true };
}
}
-----------------------------------
これをすると
title: '' or title: 'Access Denied' or title" null, error: true になってしまう
外部サイトがCDNを使って画像を表示している場合、CDNのアクセス制限で'Access Denied'が返る
また、node-fetchはブラウザのようにCookieやReferer、User-Agentを送信しないのでアクセスが成功しない結果、
title: '' となって空になる
const res = await fetch(url, {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
"Accept": "text/html",
"Referer": url,
},
});
のようにしてnode-fetchにUser-Agentをつけたがだめだった
ブラウザ側(Home.jsx)でFetchしてみたけどそれもCORSエラーとなってしまった
-----------------------------------
// 複数URLをまとめて処理
app.post("/get-title", async(req, res) => {
const { urls } = req.body;
if (!urls || !Array.isArray(urls)) {
return res.status(400).json({ error: "urls配列が必要です" });
}
//
const results = await Promise.all(urls.map(fetchTitle));
res.json(results);
});
app.listen(3000, () => console.log("Server running on http://localhost:3000"));
import { useState, useRef } from 'react';
export default function CaptureFrame() {
const videoRef = useRef(null);
const [preview, setPreview] = useState(null);
const [result, setResult] = useState(null);
const [productNames, setProductNames] = useState([]);
const fetchProductName = async (urls) => {
try {
const res = await fetch("http://localhost:3000/get-title", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ urls })
});
return await res.json();
} catch (err) {
console.error("製品名取得エラー", err);
return [];
}
};
const analyze = async () => {
if (!preview) {
alert("まずキャプチャを作成してください");
return;
}
try {
const res = await fetch("http://localhost:3000/analyze", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ image: preview })
});
const jsondata = await res.json();
console.log("解析結果:", jsondata);
setResult(jsondata);
// visuallySimilarImagesのURL上位5件を取得してstateに保存
if (jsondata.visuallySimilarImages?.length > 0) {
const urls = jsondata.visuallySimilarImages.slice(0, 5).map((img) => img.url);
const productTitles = await fetchProductName(urls);
console.log("推定製品名:", productTitle);
setProductName(productTitles);
}
} catch (err) {
console.error("CaptureFrameエラー", err);
}
}
return (
{productNames.length > 0 && (
<div>
<h3>推定製品名</h3>
<ul>
{productNames.map((productName, index)) => (
<li key={index}>
<img src={productName.url} />
<p>{productName.title}</p>
</li>
)}
</ul>
</div>
)}
);
}