「Kindleセール速報」系のサイトは、鮮度を売りにするあまり存在しないセールを断定してしまうのが最大の事故だ。自作の「マンガセール情報」(manga.autoarticles.net)は、そこを設計レベルで防いでいる。生成器 build.js は依存ゼロのNodeで、data/articles.json から記事ページを吐くが、その手前に「実在検証」の明文化されたルールがある。
断定してよいのは2種類だけ
特定作品の「今◯◯円」「今半額」「無料」「期限」を断定して載せてよいのは、次のいずれかを満たすときだけだ。
- (A) 確認済みセール: WebSearch や Amazonの商品・キャンペーンページで、当該セールが現に実施中であることを確認できたもの。この場合も
confirmed(確認日)を記録し、本文に「価格・実施状況は変動。必ずAmazonで最新を確認」と明記する。
- (B) 恒常的な仕組み: まとめ買いポイント還元、日替わり・月替わりセール、期間限定無料、Kindle Unlimited、出版社フェアなど、常に存在する仕組みを、断定的な割引率を出さずに「探し方・仕組み」として紹介する。
存在を確認できないセールは記事化しない。疑わしければ(B)にとどめる。confirmed が無い記事は date を確認日として表示する。この割り切りが、鮮度と信頼性の両立を可能にしている。
長尾SEOとFAQ構造化
狙うクエリは一般語ではなく「<作品/シリーズ> Kindle セール いつまで」「<出版社> 半額 <月>」「<シリーズ> まとめ買い 還元」のような検索意図が明確な長尾だ。各記事には実データから生成した FAQPage を付け(捏造しない)、詳細ページは Article+BreadcrumbList を持つ。FAQの質問・回答は画面表示と一致させる。
実際に試す
依存ゼロで、(A)/(B)の分岐・confirmed日付・FAQ構造化の核をNodeで再現する。manga-build.js として保存し node manga-build.js(Node 18以上)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| const fs = require("fs");
const articles = [ { slug: "series-x-sale", title: "シリーズX Kindleセール", kind: "confirmed", confirmed: "2026-07-12", detail: "対象巻がセール中。対象・条件・期間は変動する。" }, { slug: "matomegai-point", title: "まとめ買いポイント還元の探し方", kind: "evergreen", date: "2026-07-12", detail: "まとめ買いで還元される仕組みの探し方を紹介。" }, { slug: "unverified", title: "全作品いま半額", kind: "confirmed" }, ];
function accept(a) { if (a.kind === "confirmed") return !!a.confirmed; if (a.kind === "evergreen") return true; return false; }
function faqFor(a) { const conf = a.confirmed || a.date; const q = a.kind === "confirmed" ? { q: `${a.title}はいつまで?`, a: `実施状況・価格は変動します(確認日 ${conf})。必ずAmazonで最新をご確認ください。` } : { q: `${a.title}とは?`, a: `恒常的に存在する仕組みの探し方です(${conf} 時点)。` }; return [q]; }
fs.mkdirSync("public", { recursive: true }); for (const a of articles.filter(accept)) { const conf = a.confirmed || a.date; const faq = faqFor(a); const faqLd = { "@context": "https://schema.org", "@type": "FAQPage", mainEntity: faq.map((f) => ({ "@type": "Question", name: f.q, acceptedAnswer: { "@type": "Answer", text: f.a } })), }; const note = a.kind === "confirmed" ? "<p>価格・実施状況は変動します。必ずAmazonで最新を確認してください。</p>" : ""; const html = `<!DOCTYPE html><html lang="ja"><head><meta charset="utf-8"> <title>${a.title}</title> <script type="application/ld+json">${JSON.stringify(faqLd)}</script> </head><body><h1>${a.title}</h1><p>確認日: ${conf}</p><p>${a.detail}</p> ${note}<dl>${faq.map((f)=>`<dt>${f.q}</dt><dd>${f.a}</dd>`).join("")}</dl></body></html>`; fs.writeFileSync(`public/${a.slug}.html`, html); } console.log("built:", articles.filter(accept).map((a) => a.slug));
|
期待される出力:
- コンソールに
built: [ 'series-x-sale', 'matomegai-point' ] と出る(confirmed の無い断定記事は除外)。
- 確認済み記事のHTMLには「価格・実施状況は変動」の注記が入り、
confirmed 日付が表示される。
- FAQの質問文がHTMLの
<dt> と JSON-LD で一致している。
実際のセール情報と探し方の記事は マンガセール情報 で確認できる。
まとめ
- 断定してよいのは(A)確認済みと(B)恒常的な仕組みだけ。確認できないものは記事化しない。
- (A)には
confirmed と変動注記を強制する。
- 長尾クエリを狙い、FAQは実データから生成して画面表示と一致させる。