爬虫入门 爬取 网站 图片

9 阅读2分钟
const fs = require('fs');
const path = require('path');
const axios = require('axios');
const cheerio = require('cheerio');

// 网站题目列表
const titles = [
    "1. 题目1",
    "2. 题目2",
    "3. 题目3",
];

// 基础URL
const baseUrl = 'https://xxx.xxx.com';

// 创建图片下载目录
const imageDir = path.join(__dirname, 'images');
if (!fs.existsSync(imageDir)) {
    fs.mkdirSync(imageDir, { recursive: true });
}

// 下载图片的函数
async function downloadImage(url, filename) {
    console.log('开始下载图片:', url);
    try {
        const response = await axios({
            method: 'GET',
            url: url,
            responseType: 'stream'
        });

        const writer = fs.createWriteStream(path.join(imageDir, filename));

        response.data.pipe(writer);

        return new Promise((resolve, reject) => {
            writer.on('finish', resolve);
            writer.on('error', reject);
        });
    } catch (error) {
        console.error(`下载图片失败: ${url}`, error.message);
    }
}

// 获取页面中的图片URL
async function getImagesFromPage(url) {
    try {
        const response = await axios.get(url);
        console.log(response,'response');
        
        const $ = cheerio.load(response.data);
       
        const images = [];
        $('img').each((index, element) => {
            const src = $(element).attr('src');
            console.log('图片地址',src);
            
            if (src) {
                // 处理相对路径和绝对路径
                images.push('https:' + src);
            }
        });
        
        return images;
    } catch (error) {
        console.error(`获取页面图片失败: ${url}`, error.message);
        return [];
    }
}



// 主函数
async function main() {
    console.log('开始下载图片...');
    
    for (let i = 0; i < titles.length; i++) {
        const title = titles[i];
        const encodedTitle = encodeURIComponent(title);
        const pageUrl = `${baseUrl}/${encodedTitle}.html`;
        
        console.log(`正在处理第 ${i+1}/${titles.length} 个页面: ${title}`);
        
        try {
            // 获取页面中的图片
            const imageUrls = await getImagesFromPage(pageUrl);
            console.log('imageUrls',imageUrls);
            
            if (imageUrls.length === 0) {
                console.log(`  - 页面中没有找到图片`);
                continue;
            }
            
            console.log(`  - 发现 ${imageUrls.length} 张图片`);
            
            // 为每个页面创建子目录
        
            
            // 下载每张图片
            for (let j = 0; j < imageUrls.length; j++) {
                const imageUrl = imageUrls[j];
                const filename = path.basename(imageUrl);
                
                console.log(` 下载图片: ${filename}`);
                
                await downloadImage(imageUrl, filename);
            }
        } catch (error) {
            console.error(`处理页面失败: ${pageUrl}`, error.message);
        }
    }
    
    console.log('图片下载完成!');
}

// 运行主函数
main().catch(console.error);

这段 JavaScript 代码是一个 Node.js 脚本,用于 批量从指定网页中抓取并下载图片。它使用了 axios(发送 HTTP 请求)、cheerio(类似 jQuery 的 HTML 解析库)和 Node.js 内置的 fspath 模块来完成任务。

下面逐部分详细解释其功能和逻辑:


🔧 1. 引入依赖模块

const fs = require('fs');
const path = require('path');
const axios = require('axios');
const cheerio = require('cheerio');
  • fs:用于文件系统操作(如创建目录、写入文件)。
  • path:处理文件路径(跨平台兼容)。
  • axios:发起 HTTP 请求(获取网页内容、下载图片)。
  • cheerio:在服务器端解析 HTML,提供类似 jQuery 的 API 来操作 DOM。

✅ 注意:你需要先安装这些依赖:

npm install axios cheerio

📋 2. 配置数据

const titles = [
    "1. 题目1",
    "2. 题目2",
    "3. 题目3",
];

const baseUrl = 'https://xxx.xxx.com';
  • titles:要抓取的页面“标题”列表(实际用作 URL 路径的一部分)。
  • baseUrl:网站的根域名(示例中为占位符 xxx.xxx.com,需替换为真实地址)。

📁 3. 创建图片保存目录

const imageDir = path.join(__dirname, 'images');
if (!fs.existsSync(imageDir)) {
    fs.mkdirSync(imageDir, { recursive: true });
}
  • 在当前脚本所在目录下创建一个名为 images 的文件夹,用于存放下载的图片。
  • { recursive: true } 确保即使父目录不存在也能创建。

🖼️ 4. 下载单张图片函数

async function downloadImage(url, filename) {
    console.log('开始下载图片:', url);
    try {
        const response = await axios({
            method: 'GET',
            url: url,
            responseType: 'stream'
        });

        const writer = fs.createWriteStream(path.join(imageDir, filename));
        response.data.pipe(writer);

        return new Promise((resolve, reject) => {
            writer.on('finish', resolve);
            writer.on('error', reject);
        });
    } catch (error) {
        console.error(`下载图片失败: ${url}`, error.message);
    }
}
  • 使用 流式下载responseType: 'stream'),避免大图占用过多内存。
  • 将响应数据通过 .pipe() 直接写入本地文件。
  • 返回一个 Promise,确保 await 能正确等待下载完成。

🕵️ 5. 从网页提取图片 URL

async function getImagesFromPage(url) {
    try {
        const response = await axios.get(url);
        const $ = cheerio.load(response.data);
       
        const images = [];
        $('img').each((index, element) => {
            const src = $(element).attr('src');
            if (src) {
                // 处理相对路径和绝对路径
                images.push('https:' + src);
            }
        });
        
        return images;
    } catch (error) {
        console.error(`获取页面图片失败: ${url}`, error.message);
        return [];
    }
}
  • axios.get 获取网页 HTML。
  • cheerio.load 解析 HTML,然后遍历所有 <img> 标签。
  • 提取每个 src 属性,并强制加上 https: 前缀

🚀 6. 主流程函数 main()

async function main() {
    console.log('开始下载图片...');
    
    for (let i = 0; i < titles.length; i++) {
        const title = titles[i];
        const encodedTitle = encodeURIComponent(title);
        const pageUrl = `${baseUrl}/${encodedTitle}.html`;
        
        console.log(`正在处理第 ${i+1}/${titles.length} 个页面: ${title}`);
        
        try {
            const imageUrls = await getImagesFromPage(pageUrl);
            
            if (imageUrls.length === 0) {
                console.log(`  - 页面中没有找到图片`);
                continue;
            }
            
            console.log(`  - 发现 ${imageUrls.length} 张图片`);
            
            // 下载每张图片
            for (let j = 0; j < imageUrls.length; j++) {
                const imageUrl = imageUrls[j];
                const filename = path.basename(imageUrl);
                await downloadImage(imageUrl, filename);
            }
        } catch (error) {
            console.error(`处理页面失败: ${pageUrl}`, error.message);
        }
    }
    
    console.log('图片下载完成!');
}
  • 遍历 titles 数组,为每个标题生成对应的页面 URL。
  • 对每个页面:
    1. 抓取 HTML;
    2. 提取所有 <img src="...">
    3. 逐个下载图片,文件名取自 URL 最后一段(如 a.jpg)。

▶️ 7. 启动脚本

main().catch(console.error);
  • 调用主函数,并捕获顶层异常防止崩溃。

✅ 总结:这段代码的作用

自动访问多个网页 → 提取所有 <img> 标签的图片链接 → 下载这些图片到本地 images 文件夹。

适用场景

  • 批量下载某个网站题库/文章中的配图。
  • 网站内容备份(仅图片)。
  • 爬虫入门练习。