1、主进程

const http = require('http');
const fs = require('fs');
const cheerio = require('cheerio');
const request = require('request');
const makePool = require('./pooler')
const runJob = makePool('./worker')
var i = 0;
var url = "http://xxx.com/articles/";
//初始url
let g = '';
function fetchPage(x) { //封装了一层函数
console.log(x)
if(!x || x==''){
g.next()
return
}
startRequest(x);
} function startRequest(x) {
//采用http模块向服务器发起一次get请求
return http.get(x, function (res) {
var html = ''; //用来存储请求网页的整个html内容
var titles = [];
res.setEncoding('utf-8'); //防止中文乱码
//监听data事件,每次取一块数据
res.on('data', function (chunk) {
html += chunk;
});
//监听end事件,如果整个网页内容的html都获取完毕,就执行回调函数
res.on('end', function () {
var $ = cheerio.load(html); //采用cheerio模块解析html var time = new Date();
var p = $('.content p')
p.each((index,item)=>{
if($(item).find('strong').length) {
var fex_item = {
//获取文章的标题
title: $(item).find('strong').text().trim(),
//获取文章发布的时间
time: time,
//获取当前文章的url
link: $($(item).children('a').get(0)).attr('href'),
des:$(item).children().remove()&&$(item).text(),
//i是用来判断获取了多少篇文章
i: index+1 };
runJob(fex_item,(err,data)=>{
if(err) console.error('get link error')
console.log('get link ok')
})
} })
g.next()
}) }).on('error', function (err) {
console.log(err);
g.next()
}); }
function* gen(urls){
let len = urls.length;
for(var i=0;i<len;i++){
yield fetchPage(urls[i])
}
} function getUrl(x){
//采用http模块向服务器发起一次get请求
http.get(x, function (res) {
var html = ''; //用来存储请求网页的整个html内容
var titles = [];
res.setEncoding('utf-8'); //防止中文乱码
//监听data事件,每次取一块数据
res.on('data', function (chunk) {
html += chunk;
});
//监听end事件,如果整个网页内容的html都获取完毕,就执行回调函数
res.on('end', function () {
var $ = cheerio.load(html); //采用cheerio模块解析html var time = new Date();
var lists = $('.articles .post-list li')
var urls = [];
lists.each(function(index,item){
if($(item).find('a').length) {
var url = 'http://xxxx.com'+$($(item).children('a').get(0)).attr('href');
if(url)
urls.push(url); //主程序开始运行
}
})
g = gen(urls)
g.next()
}) }).on('error', function (err) {
console.log(err);
});
} getUrl(url)

2、创建进程池

const cp = require('child_process')
const cpus = require('os').cpus().length; module.exports = function pooler(workModule){
let awaiting = [],readyPool = [],poolSize = 0;
return function doWork(job,cb){
if(!readyPool.length&&poolSize>cpus)
return awaiting.push([doWork,job,cb]) let child = readyPool.length ? readyPool.shift():(poolSize++,cp.fork(workModule))
let cbTriggered = false;
child.removeAllListeners()
.once('error',function(err){
if(!cbTriggered){
cb(err)
cbTriggered = true
}
child.kill()
})
.once('eixt',function(){
if(!cbTriggered)
cb(new Error('childe exited with code:'+code))
poolSize--;
let childIdx = readyPool.indexOf(child)
if(childIdx > -1)readyPool.splice(childIdx,1)
})
.once('message',function(msg){
cb(null,msg)
cbTriggered = true
readyPool.push(child)
if(awaiting.length)setImmediate.apply(null,awaiting.shift())
})
.send(job)
}
}

3、工作进程接受消息并处理内容

const fs = require('fs')
process.on('message',function(job){
let _job = job
let x = 'TITLE:'+_job.title+'\n' + 'LINK:'+_job.link + '\n DES:'+_job.des+'\n SAVE-TIME:'+_job.time fs.writeFile('../xx/data/' + _job.title + '.txt', x, 'utf-8', function (err) {
if (err) {
console.log(err);
}
});
process.send('finish')
})

从零系列--node爬虫利用进程池写数据的更多相关文章

  1. python系列之 - 并发编程(进程池,线程池,协程)

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  2. Python之进程 3 - 进程池和multiprocess.Poll

    一.为什么要有进程池? 在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务.那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗 ...

  3. (7)Pool进程池

    (1)# 开启过多的进程并不一定提高你的效率 因为进程池可以实现并行的概念,比Process单核并发的速度要快 # 如果cpu负载任务过多,平均单个任务执行的效率就会低,反而降低执行速度. 1个人做4 ...

  4. python基础-UDP、进程、进程池、paramike模块

    1 基于UDP套接字1.1 介绍 udp是无连接的,是数据报协议,先启动哪端都不会报错 udp服务端 import socket sk = socket() #创建一个服务器的套接字 sk.bind( ...

  5. 运用pool进程池启动大量子进程

    # Pool进程池类 from multiprocessing import Pool import os import time import random def run(index): prin ...

  6. 进程池(Pool)

    进程池用于进程维护, 当使用时,将会去进程池取数据 from multiprocessing import Pool, Processimport os, time def f(i): time.sl ...

  7. python爬虫之线程池和进程池

    一.需求 最近准备爬取某电商网站的数据,先不考虑代理.分布式,先说效率问题(当然你要是请求的太快就会被封掉,亲测,400个请求过去,服务器直接拒绝连接,心碎),步入正题.一般情况下小白的我们第一个想到 ...

  8. python编程系列---进程池的优越性体验

    1.通过multiprocessing.Process()类创建子进程 import multiprocessing, time, os, random def work(index): " ...

  9. 进程池与回调函数与正则表达式和re爬虫例子

    # 使用进程池的进程爬取网页内容,使用回调函数处理数据,用到了正则表达式和re模块 import re from urllib.request import urlopen from multipro ...

随机推荐

  1. jQuery事件处理

    浏览器的事件模型 DOM第0级事件模型 Event实例 他的属性提供了关于当前正被处理的已触发事件的大量信息.这包括一些细节,比如在哪个元素上触发的事件.鼠标事件的坐标以及键盘事件中单击了哪个键. 事 ...

  2. 4034. [HAOI2015]树上操作【树链剖分】

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...

  3. Win10右键添加获取管理员权限

    在win10中,还是和WIN7/8一样很多文件被设置权限我们打不开,但很多时候我们还是要打开这些文件夹的,尤其是数据恢复和电脑维护优化时.于是乎我们就有必要获取管理员权限.本人隆重退出完美解决方法. ...

  4. ajax跨域调用webservice例子

    [WebMethod(Description = "这是一个描述")] public void GetTIM() { try { SqlDataAdapter da = new S ...

  5. dbcp最终版本

    注意:我们在使用有参的queryrunner的时候,不需要关闭connection和DataSource 这些都queryrunner 都替我们完成.我们不需要关系资源释放. 工具类: package ...

  6. ddt Ui 案例2

    准备用例文件:testcase1.py testcase2.py import ddt import unittest from HTMLTestRunner import HTMLTestRunne ...

  7. Kafka设计解析(六)Kafka高性能架构之道

    转载自 技术世界,原文链接 Kafka设计解析(六)- Kafka高性能架构之道 本文从宏观架构层面和微观实现层面分析了Kafka如何实现高性能.包含Kafka如何利用Partition实现并行处理和 ...

  8. 一个牛公司的关于oracle数据的面试题

    我也忘记是从哪里download的了,为了加深记忆,也为了完成我的博客,我决定写进博客里,如果有错误,欢迎大家指正,谢谢. 问题一. 解释一下sum的作用? 答:求符合条件的记录某数值字段的和. 问题 ...

  9. Python虚拟环境包导出

    一.导出包文件 1.进入虚拟环境 2.进入项目目录下创建放置包文件的文件夹(whls) mkdir whls 3.进入whls文件夹,执行导出命令 (导入包时有网络) cd whls pip free ...

  10. 安装好XAMPP+安装好PhpStorm 然后搭建PHP开发环境

    1.安装XAMPP 1.1.可以参考我的这篇博客:XMAPP的安装与配置. 2.安装并破解PhpStorm 2.1.可以参考我的这篇博客:PhpStorm2016.2版本安装与破解. 3.配置PhpS ...