指量抓取,大家有没有好的Nodejs解决方案?

指量抓取,大家有没有好的Nodejs解决方案?

指量抓取,大家有没有好的解决方案?, 抓取的页面在10W左右。我现在用request这个模块,总感觉不稳定。进程会动不动就不运行了(没有退出,卡住了),现在不知道卡在了哪儿。我设置timeout的话,一下子全超时了。

3 回复

指量抓取,大家有没有好的Node.js解决方案?

在进行大规模网页抓取时,处理好性能、稳定性和错误处理是非常重要的。如果你目前使用的是request模块,并且遇到了一些问题(如不稳定、进程卡住等),可以考虑使用更现代和强大的工具,例如axios或者node-fetch。此外,为了更好地管理并发请求,可以结合使用async/await以及Promise.all

以下是一个使用axiosasync/await来实现高效稳定的网页抓取的示例:

示例代码

const axios = require('axios');
const fs = require('fs');
const path = require('path');

// 定义要抓取的URL列表
const urls = [
    'http://example.com/page1',
    'http://example.com/page2',
    // ... 更多URL
];

// 创建一个异步函数来处理每个请求
async function fetchPage(url) {
    try {
        const response = await axios.get(url, {
            timeout: 5000, // 设置超时时间
            maxRedirects: 5, // 处理重定向
        });
        return response.data;
    } catch (error) {
        console.error(`Error fetching ${url}:`, error.message);
        return null;
    }
}

// 使用Promise.all来并发处理所有请求
async function main() {
    const results = await Promise.all(urls.map(fetchPage));

    // 将结果保存到文件中
    const outputFilePath = path.join(__dirname, 'output.txt');
    fs.writeFileSync(outputFilePath, results.join('\n'));
    
    console.log(`Data saved to ${outputFilePath}`);
}

main().catch(console.error);

解释

  1. 依赖引入

    • axios 是一个基于Promise的HTTP客户端,适用于浏览器和Node.js。
    • fspath 是Node.js内置模块,用于文件系统操作和路径处理。
  2. 定义URL列表

    • urls 数组包含了所有需要抓取的页面URL。
  3. 创建异步函数 fetchPage

    • 使用 axios.get 方法发送GET请求。
    • 设置超时时间和最大重定向次数,以提高稳定性。
    • 使用 try/catch 块来捕获并记录任何可能发生的错误。
  4. 并发处理请求

    • 使用 Promise.all 并发执行所有的 fetchPage 函数。
    • 当所有请求完成后,将结果合并成一个数组。
  5. 保存结果

    • 将结果数组写入到文件中,方便后续处理。

通过这种方式,你可以更有效地管理和监控大量请求,同时确保代码的稳定性和可维护性。


我在使用Needle,你可以试用一下 https://github.com/tomas/needle

针对你的需求,你可以使用 axiospuppeteer 来实现更稳定、更高效的网页抓取。这两个库提供了更强大的功能来处理复杂的网页结构以及更好的错误处理机制。

这里提供一个简单的示例代码,展示如何使用 axios 进行并发抓取:

const axios = require('axios');
const async = require('async');

const urls = Array.from({length: 100000}, (_, i) => `https://example.com/page${i + 1}`);

const MAX_CONCURRENT_REQUESTS = 50;

async function fetchUrl(url) {
    try {
        const response = await axios.get(url, { timeout: 10000 });
        console.log(`Fetched ${url}:`, response.data);
    } catch (error) {
        console.error(`Error fetching ${url}:`, error.message);
    }
}

async function fetchUrlsInBatches(urls, batchSize) {
    return new Promise((resolve) => {
        async.whilst(
            () => urls.length > 0,
            (cb) => {
                const batch = urls.splice(0, batchSize);
                async.eachLimit(batch, MAX_CONCURRENT_REQUESTS, fetchUrl, cb);
            },
            resolve
        );
    });
}

fetchUrlsInBatches(urls, MAX_CONCURRENT_REQUESTS);

代码说明

  1. axios: 这个库用于发送 HTTP 请求。它比 request 更现代,并且具有更好的错误处理机制。
  2. async: 提供了 eachLimit 方法,可以限制并发请求的数量。
  3. MAX_CONCURRENT_REQUESTS: 控制并发请求数量,防止服务器因请求过多而被封锁。
  4. fetchUrl: 处理单个 URL 的抓取逻辑。
  5. fetchUrlsInBatches: 将 URL 列表分成多个批次进行抓取,确保不会一次性发起大量请求。

优化建议

  • 如果你需要处理动态加载的数据(如通过 JavaScript 加载的内容),考虑使用 puppeteer
  • 使用 puppeteer 可以更好地模拟浏览器行为,处理登录、cookies 等复杂场景。
  • 可以通过设置合理的重试机制来提高稳定性,例如使用 retry-as-promisedp-retry 库。

希望这段代码能帮助你解决当前的问题。

回到顶部