当然可以,下面是一个更完整的 TypeScript 爬虫实例,它不仅使用 TypeScript,还展示了一些常见的爬虫技巧,比如递归抓取和存储抓取结果。

步骤一:设置项目

  1. 创建一个新的项目目录并初始化 Bun 项目:

    mkdir my-web-crawler
    cd my-web-crawler
    bun init
  2. 安装 TypeScript 和相关类型定义:

    bun add -d typescript @types/node
  3. 初始化 TypeScript 配置文件:

    npx tsc --init

步骤二:安装所需依赖

安装用于 HTTP 请求和 HTML 解析的库:

bun add axios cheerio

步骤三:编写爬虫代码

创建一个 src 目录并在其中创建一个 crawler.ts 文件:

// src/crawler.ts
 
import axios from 'axios';
import cheerio from 'cheerio';
import * as fs from 'fs';
 
const startUrl = 'https://example.com'; // 你要抓取的起始网站URL
const visitedUrls = new Set<string>();
const maxDepth = 2;
 
async function fetchHTML(url: string): Promise<string> {
  const { data } = await axios.get(url);
  return data;
}
 
async function parseHTML(url: string, html: string, depth: number): Promise<void> {
  const $ = cheerio.load(html);
  const links: string[] = [];
 
  $('a').each((index, element) => {
    const link = $(element).attr('href');
    if (link && isValidUrl(link)) {
      links.push(new URL(link, url).href);
    }
  });
 
  saveLinksToFile(url, links);
 
  if (depth < maxDepth) {
    for (const link of links) {
      if (!visitedUrls.has(link)) {
        visitedUrls.add(link);
        await crawl(link, depth + 1);
      }
    }
  }
}
 
function isValidUrl(link: string): boolean {
  return link.startsWith('http');
}
 
function saveLinksToFile(url: string, links: string[]): void {
  const fileName = 'crawled_links.txt';
  const data = `URL: ${url}\nLinks:\n${links.join('\n')}\n\n`;
  fs.appendFileSync(fileName, data);
}
 
async function crawl(url: string, depth: number): Promise<void> {
  try {
    const html = await fetchHTML(url);
    await parseHTML(url, html, depth);
  } catch (error) {
    console.error(`Error occurred while crawling ${url}:`, error);
  }
}
 
async function main() {
  visitedUrls.add(startUrl);
  await crawl(startUrl, 0);
}
 
main();

步骤四:配置 TypeScript

编辑 tsconfig.json,确保编译目标和模块解析适用于 Bun 环境:

{
  "compilerOptions": {
    "target": "es2020",
    "module": "esnext",
    "moduleResolution": "node",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src"]
}

步骤五:编译并运行爬虫

编译 TypeScript 代码:

bun tsc

运行编译后的 JavaScript 代码:

bun run dist/crawler.js

代码解释

  1. fetchHTML 函数: 使用 axios 库发送 HTTP GET 请求并返回 HTML 字符串。
  2. parseHTML 函数: 使用 cheerio 库解析 HTML 并提取所有链接,递归抓取到指定深度。
  3. isValidUrl 函数: 检查链接是否是有效的 URL。
  4. saveLinksToFile 函数: 将抓取的链接保存到一个文件中。
  5. crawl 函数: 控制抓取过程,防止重复抓取已访问的 URL。
  6. main 函数: 初始化抓取过程。

通过这个示例,你可以了解如何在 Bun 环境下使用 TypeScript 编写一个递归爬虫,并保存抓取结果到文件。你可以根据需要进一步扩展这个爬虫,比如添加更多的抓取策略、处理不同的 HTML 结构等。