当前位置:AIGC资讯 > 数据采集 > 正文

js - 爬虫的实现

爬虫的原理

爬虫,就是一个自动爬取网页上展示的信息的工具。我们要写一款爬虫,就要满足下面的条件:

网络的请求。首先我们要进行网络请求,让目标给我们返回信息(常用的模块有http、http2、https、request、axios、puppeteer) 对返回来的数据的处理。(这部分可以随意发挥、正则等技术,而对于html文件的话,有 cheerio 模块(客户端的jQuery)、而返回来的数据可能有编码问题,iconv-lite 模块可以用于编码的转换,当然,请求时也可以直接设置response的编码) 数据的储存。(这部分涉及到文件处理和数据库,会在另外的文章叙述)

爬虫的实现

    talk is cheap,show me the code

    让我们开始写代码吧

const cheerio = require('cheerio');
const fs = require('fs');
const request = require('request');

// http://www.feizdy.com 是一个电影网站
// 尝试的时候建议选用http的网站,初学者比较好爬
// 我们的目的是爬取电影的名称和图片信息,并把图片下载保存起来

// target
let url = 'http://www.feizdy.com';
// savePath
let photoSavePath = './img';

run(url, photoSavePath)
    .catch(err => {
    console.log('运行错误 => ' + err);
});

async function run(url, photoSavePath) {
    //  获得首页
    const html = await getHTML(url);

    // 可以直接用正则进行内容匹配
    // 把首页 用cheerio模块转换成Dom操作 (注意:load转换时可能会乱码,所以要设置{decodeEntities: false})
    const $ = cheerio.load(html, {decodeEntities: false});
    // 2.对返回来的数据进行处理

    // 用元素审查分析html文件结构(见图 1)
    // 元素选择器获得所需要的结构的集合

    // 这里是获得电影详情页的链接
    $('.container .row .col-sm-6 .movie-item a').each((i, item) => {
        // 这里的item要转换一下,用$(item)变成dom节点
        // 由图可以看出链接是片段的,要拼接成完整的url
        let detailUrl = url + $(item).attr('href');

        // 利用详情链接获取电影详细信息
        getDetailMessage(detailUrl)
            .then(movie => {
                return addToFile(movie);
            })
            .then(imgSrc => {
                downloadPhoto(imgSrc, photoSavePath, i);
            })
            .catch(err => {
                console.log(err);
            });
    });
}

// 请求资源
function getHTML(url, timeout = 20000) {
    return new Promise((resolve, reject) => {
        // 1.发送请求,等待网站回应
        request.get(url, {timeout: timeout}, function (error, response, body) {
            error ? reject('Timeout.\n' ) : resolve(body);
        })
    })
}

// 获得电影相关的信息
async function getDetailMessage(url) {
    try {
        let detailHTML = await getHTML(url);
        // 结构分析在图 2
        const $ = cheerio.load(detailHTML, {decodeEntities: false});
        let movie =  {
                name: await $('.container .container-fluid .row .col-md-12 .movie-title').text(),
                img:  await $('.container .container-fluid .row .col-md-9 .row .col-md-4 a img').attr('src')
            };
        // 去除空电影
        return movie.name && movie.img ? movie : undefined;
    } catch (e) {
        console.log('Method: getDetailMessage =>' + e);
    }
}

// 添加到文件
function addToFile(item) {
    if (item) {
        let imgSrc = item.img;
        item = JSON.stringify(item) + '\n';
        // 把movie 写入文件
        fs.appendFile('./data/data.txt', item, {encoding: 'utf-8', flag: 'a'}, error => {
            error ? console.log('Method: addToFile => data write error.\n' + error) : null;
        })
        return imgSrc;
    }
}


// 下载图片
function downloadPhoto(src, photoSavePath, filename, timeout = 20000) {
    if (src) {
        // 提取后缀名
        let suffix = src.toString().slice(-4);
        // 拼接路径
        let path = photoSavePath + '/' + filename + suffix;
        // 下载
        request.get(src, {timeout: timeout}, err => {
            err ? console.log('Method: downloadPhoto => download error\n' + err) : null;
        }).pipe(fs.createWriteStream(path));
    }
}

图 1

图2

更新时间 2023-11-08