Use Cases

How to Implement Web Scraping with Claude Code

Learn how to implement web scraping using Claude Code. Includes practical code examples and step-by-step guidance.

WebスクレイピングをClaude Codeで効率化する

Webスクレイピングは、データ収集や監視、競合分析などに活用される技術です。Claude Codeを使えば、HTML解析からデータ整形まで一貫したスクレイピングスクリプトを短時間で構築できます。

Cheerioで静的ページをスクレイピング

JavaScriptレンダリングが不要なページにはCheerioが最適です。

> Cheerioでニュースサイトの記事タイトルとリンクを取得するスクリプトを作って。
> リトライ機能とレート制限も入れて。
import * as cheerio from "cheerio";

interface Article {
  title: string;
  url: string;
  date?: string;
}

async function fetchWithRetry(
  url: string,
  retries = 3,
  delay = 1000
): Promise<string> {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(url, {
        headers: {
          "User-Agent": "Mozilla/5.0 (compatible; MyBot/1.0)",
        },
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      return await res.text();
    } catch (error) {
      if (i === retries - 1) throw error;
      console.log(`リトライ ${i + 1}/${retries}...`);
      await new Promise((r) => setTimeout(r, delay * (i + 1)));
    }
  }
  throw new Error("Unreachable");
}

async function scrapeArticles(url: string): Promise<Article[]> {
  const html = await fetchWithRetry(url);
  const $ = cheerio.load(html);
  const articles: Article[] = [];

  $("article, .article, .post").each((_, element) => {
    const titleEl = $(element).find("h2 a, h3 a, .title a").first();
    const title = titleEl.text().trim();
    const href = titleEl.attr("href");
    const date = $(element).find("time, .date").first().text().trim();

    if (title && href) {
      articles.push({
        title,
        url: new URL(href, url).toString(),
        date: date || undefined,
      });
    }
  });

  return articles;
}

Puppeteerで動的ページをスクレイピング

SPAやJavaScriptで描画されるページにはPuppeteerを使います。

import puppeteer from "puppeteer";

interface ProductData {
  name: string;
  price: number;
  rating: number;
  imageUrl: string;
}

async function scrapeDynamicPage(url: string): Promise<ProductData[]> {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  // 不要なリソースをブロックして高速化
  await page.setRequestInterception(true);
  page.on("request", (req) => {
    const type = req.resourceType();
    if (["image", "stylesheet", "font"].includes(type)) {
      req.abort();
    } else {
      req.continue();
    }
  });

  await page.goto(url, { waitUntil: "networkidle2" });

  // 無限スクロールで全データを読み込む
  let previousHeight = 0;
  while (true) {
    const currentHeight = await page.evaluate(() => document.body.scrollHeight);
    if (currentHeight === previousHeight) break;
    previousHeight = currentHeight;
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
    await new Promise((r) => setTimeout(r, 1500));
  }

  const products = await page.evaluate(() => {
    const items = document.querySelectorAll(".product-card");
    return Array.from(items).map((item) => ({
      name: item.querySelector(".product-name")?.textContent?.trim() || "",
      price: parseFloat(
        item.querySelector(".price")?.textContent?.replace(/[^0-9.]/g, "") || "0"
      ),
      rating: parseFloat(
        item.querySelector(".rating")?.getAttribute("data-value") || "0"
      ),
      imageUrl: item.querySelector("img")?.getAttribute("src") || "",
    }));
  });

  await browser.close();
  return products;
}

データの保存と構造化

取得したデータをJSON、CSV形式で保存します。

import fs from "fs/promises";

async function saveAsJson(data: unknown[], filePath: string) {
  await fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
  console.log(`${filePath} に ${(data as any[]).length}件を保存しました`);
}

function toCsvString(data: Record<string, unknown>[]): string {
  if (data.length === 0) return "";

  const headers = Object.keys(data[0]);
  const rows = data.map((row) =>
    headers.map((h) => {
      const val = String(row[h] ?? "");
      return val.includes(",") || val.includes('"')
        ? `"${val.replace(/"/g, '""')}"`
        : val;
    }).join(",")
  );

  return [headers.join(","), ...rows].join("\n");
}

async function saveAsCsv(data: Record<string, unknown>[], filePath: string) {
  const csv = toCsvString(data);
  await fs.writeFile(filePath, csv, "utf-8");
  console.log(`${filePath} に保存しました`);
}

定期実行とスケジューリング

import cron from "node-cron";

function startScheduledScraping() {
  // 毎日9時に実行
  cron.schedule("0 9 * * *", async () => {
    console.log(`[${new Date().toISOString()}] スクレイピング開始`);

    try {
      const articles = await scrapeArticles("https://example.com/news");
      const timestamp = new Date().toISOString().split("T")[0];
      await saveAsJson(articles, `./data/articles-${timestamp}.json`);
    } catch (error) {
      console.error("スクレイピングエラー:", error);
    }
  });

  console.log("スケジュール設定完了(毎日9:00実行)");
}

倫理的な配慮

Webスクレイピングを行う際は、以下の点に注意してください。

  • robots.txtを確認し、クローリングが許可されているか確認する
  • リクエスト間隔を適切に設けてサーバーに負荷をかけない
  • 利用規約を確認し、スクレイピングが禁止されていないか確認する
  • 取得したデータの著作権と利用目的を考慮する

Markdown形式でデータを加工する方法はMarkdown処理・変換を参照してください。CLIツールとして構築する場合はCLIツール開発もご覧ください。

Zusammenfassung

Claude Codeを使えば、静的・動的ページのスクレイピング、データ整形、定期実行まで含めたスクレイピングシステムを短時間で構築できます。セレクタの指定やデータ変換も自然言語で指示するだけです。

詳しくはClaude Code公式ドキュメントを参照してください。

#Claude Code #web scraping #Puppeteer #Cheerio #データ収集