💨
Cloudflare Browser Rendering APIでウェブサイトを単一のPDFファイルにしてダウンロードする
Cloudflare WorkersのBrowser Rendering APIのpuppeteer互換APIを使って与えられたURLの下位リンクを辿り複数ページを含む単一のPDFファイルを生成します
PDFファイルにすることで各種チャットAIサービスに入力してQ&Aできるようになります
例: Cloudflare Workersのドキュメントと対話する
実装
PDFの連結にはpdf-libを使います
ローカルで実行するだけならpuppeteerとNode.jsでもおそらく実現できます
import puppeteer from "@cloudflare/puppeteer";
import { PDFDocument } from "pdf-lib";
interface Env {
MY_BROWSER: Fetcher;
}
export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url).searchParams.get('url');
if (!url) {
return new Response('Missing URL parameter', { status: 400 });
}
const browser = await puppeteer.launch(env.MY_BROWSER);
const page = await browser.newPage();
await page.goto(url);
const subLinks = await page.evaluate((currentURL) => {
const links = Array.from(document.querySelectorAll('a'));
return links
.map((link) => link.href)
.filter((href) => href.startsWith(currentURL))
.map((link) => link.split('#')[0]);
}, url);
// Remove duplicate pages from the sub-links list
const uniqueSubLinks = Array.from(new Set([url, ...subLinks]));
const pdfDoc = await PDFDocument.create();
// Navigate to each sub-link, generate PDF, and merge into the main PDF document
for (const link of uniqueSubLinks) {
console.log(`Generating PDF for: ${link}`);
await page.goto(link);
const pdfBytes = await page.pdf({ format: 'A4' });
const subPdfDoc = await PDFDocument.load(pdfBytes);
const copiedPages = await pdfDoc.copyPages(subPdfDoc, subPdfDoc.getPageIndices());
copiedPages.forEach((page) => pdfDoc.addPage(page));
}
const pdfBytes = await pdfDoc.save();
return new Response(pdfBytes, {
headers: {
'Content-Type': 'application/pdf',
},
});
}
}
テスト
https://developers.cloudflare.com/workers/platform/
を与えたところ1.4MBのPDFファイルがダウンロードできました
61ページあります
Discussion