资讯专栏INFORMATION COLUMN

puppeteer_node爬虫分布式进阶

sutaking / 1581人阅读

摘要:前面的文章将做爬虫的基础一直到部署都梳理了一遍,现在来看一下分布式的处理为什么需要分布式需要抓取的不同数据有很多,会同时开启无头浏览器去抓取,然后获取到数据后又无厘头的一股脑挤进数据库无法保证同一时刻需要的数据只有一个操作在进行分布式选择因

前面的文章将puppeteer做爬虫的基础一直到部署都梳理了一遍,现在来看一下分布式的处理 1) 为什么需要分布式
   1. 需要抓取的不同数据有很多,会同时开启无头浏览器去抓取,然后获取到数据后又无厘头的一股脑挤进数据库
   2. 无法保证同一时刻需要的数据只有一个操作在进行
2) 分布式选择
因为使用的是node,所以尽可能的寻找node支持的分布式框架
ZooKeeper 和 RabbitMQ 的思想百度上有好多说明,读者可以自行搜索作更详细的了解
node版的zookeeper
node版的RabbitMQ
3) 衔接之前的 puppeteer进阶版_爬取书旗小说 文章内容,文章只是放了一些主要的代码,末尾会附上项目地址,大家可以去撸一撸
发布者,给书旗起一个标识为 37 (channel_id),然后是要抓取书的书籍id(channel_book_id)
// 我们以接口的形式接收爬取的参数    
// 简易版请求(除了接收参数不做任何处理) -> 发布者
app.get("/v1.0/grasp_book", (req, res, next) => {
  // 抓取时需要的参数
  if (!req.query.channel_id && !req.query.channel_book_id) {
    res.send({
      code: 403,
      msg: "params error"
    })
    return null;
  }
  // 发布者
  // 连接rabbitmq
  amqp.connect("amqp://rabbitmq:12345678@127.0.0.1:5672/").then(function(conn) {
    return conn.createChannel().then(function(ch) {
      // 创建 hello 的消息队列
      var q = "hello";
      // 解析为json字符串格式作为传递的数据格式
      var msg = JSON.stringify({
        "channel_id": req.query.channel_id,
        "book_id": req.query.book_id
      })
      // 连接并保持
      var ok = ch.assertQueue(q, {durable: true});
      return ok.then(function(_qok) {
        // 发送数据到消费者
        ch.sendToQueue(q, Buffer.from(msg));
        console.log(" [x] Sent "%s"", msg);
        return ch.close();
      });
    }).finally(function() { conn.close(); });
  }).catch(console.warn);
  res.send({
    code: 200,
    msg: "success"
  });
}); 
命令行启动app.js,发出请求并查看结果,{} 里面的就是我们发送出去的数据


消费者以及ZooKeeper
消费者,接收到发布者传递过来的数据建立消息队列,然后用Zookeeper创建临时节点以保持队列依次执行
var zookeeper = require("node-zookeeper-client");

// 根据标识动态引入js文件
function moduleCustomize(channel_id) {
    return require(`../${channel_id}.js`)
}

 
var client = zookeeper.createClient("127.0.0.1:2181");

async function sleep(second) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("sleep")
    }, second)
  })
}

// 连接_zookeeper
client.once("connected", function () {
  console.log("Connected to the server.");
  // 建立连接 rabbitmp
  amqp.connect("amqp://rabbitmq:12345678@127.0.0.1:5672/").then(function(conn) {
    return conn.createChannel().then(function(ch) {
      // 与名为 hello(由发布者创建) 的消息队列建立连接
      var ok = ch.assertQueue("hello", {durable: true});
      // 预存为1
      ok = ok.then(function() { ch.prefetch(1); });
      ok = ok.then(function() {
        // doWork 回调函数 -> 执行接收到数据后的操作
        ch.consume("hello", doWork, {noAck: false});
      });
      return ok;
      // rabbitmq 处理
      function doWork(msg) {
          // 接收到数据
          var body = msg.content.toString();
          console.log("[x] Received "%s"", body);
          let _body = JSON.parse(body)
          let channel_book_id = _body["channel_book_id"];
          let channel_id = _body["channel_id"];
          // zookeeper 节点
          let path = `/${channel_id + "_" + channel_book_id}`
          // 连接_zookeeper 判断是否存在
          client.exists(path, function (error, stat) {
              if (error) {
                  console.log(error.stack);
                  return;
              }
              if (stat) {
                console.log("Node exists.");
                // 存在则不执行,但需要将数据传递下去
                // ack 可以参考 https://www.jianshu.com/p/a5f7fce67803
                ch.ack(msg);
              } else {
                  console.log("Node does not exist.");
                  // 操作完成后则释放当前创建的临时节点
                  client.create(path, null, zookeeper.CreateMode.EPHEMERAL, function (error) {
                    if (error) {
                        console.log("Failed to create node: %s due to: %s.", path, error);
                    } else {
                        console.log("Node: %s is successfully created.", path);
                          
                        // 根据传入标识(如书旗就是37)动态引入js文件(抓书的操作)
                        moduleCustomize(channel_id).init(channel_book_id)

                        // 传递数据
                        ch.ack(msg);
                        // 释放当前创建的临时节点
                        client.remove(path, -1, function (error) {
                            if (error) {
                                console.log(error.stack);
                                return;
                            }
                            console.log("Node is deleted.");
                        });

                    }
                  });
                }
              console.log("任务执行完毕")
            });
      }
    });
  }).catch(console.warn);


});
 
client.connect();
命令行启动rab_consumer.js,{} 里面就是我们接收到消息队列里面的数据了

4) 查看mongo结果数据

5) 项目地址(update分支)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93256.html

相关文章

  • 非计算机专业小白自学爬虫全指南(附资源)

    摘要:爬虫是我接触计算机编程的入门。练练练本文推荐的资源就是以项目练习带动爬虫学习,囊括了大部分爬虫工程师要求的知识点。拓展阅读一文了解爬虫与反爬虫最后,请注意,爬虫的工作机会相对较少。 爬虫是我接触计算机编程的入门。哥当年写第一行代码的时候别提有多痛苦。 本文旨在用一篇文章说透爬虫如何自学可以达到找工作的要求。 爬虫的学习就是跟着实际项目去学,每个项目会涉及到不同的知识点,项目做多了,自然...

    CarlBenjamin 评论0 收藏0
  • 超详细的Python实现百度云盘模拟登陆(模拟登陆进阶)

    摘要:方法不仅适用于百度云,别的一些比较难以模拟登陆的网站都可以按照这种方式分析。本文要求读者具有模拟登陆主要是抓包和阅读代码和密码学的基本知识。和模拟登陆微博的分析流程一样,我们首先要做的是以正常人的流程完整的登录一遍百度网盘。 这是第二篇从简书搬运过来的文章(大家别误会,是我原创的)。因为前一篇文章,我看反响还挺好的,所以把这篇也搬运过来了,其实目的还是为宣传自己的分布式微博爬虫(该项目...

    CarterLi 评论0 收藏0
  • 零基础如何学爬虫技术

    摘要:楚江数据是专业的互联网数据技术服务,现整理出零基础如何学爬虫技术以供学习,。本文来源知乎作者路人甲链接楚江数据提供网站数据采集和爬虫软件定制开发服务,服务范围涵盖社交网络电子商务分类信息学术研究等。 楚江数据是专业的互联网数据技术服务,现整理出零基础如何学爬虫技术以供学习,http://www.chujiangdata.com。 第一:Python爬虫学习系列教程(来源于某博主:htt...

    KunMinX 评论0 收藏0
  • Python从入门到转行

    摘要:学了大半年之后成功转行做前端了。包含大量其他神经网络库中的包装器和抽象,其中最值得注意的是,其中也包含一些机器学习的实用模块。它是轻量级可扩展的神经网络工具包,同时拥有友好的界面,可供机器学习的训练和预测使用。 题记:大二的时候发现人生苦短,所以信了拍神,开始学Python。学了大半年之后成功转行做前端了。来写个教程帮助大家入门Python。 Python零基础入门 零基础入门就得从最...

    ingood 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<