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. iOS网络缓存的系统实现是一个烂尾工程

    烂尾的原因是request的一致性比较接口没有开放出来.

  2. BZOJ4522:[CQOI2016]密钥破解(Pollard-Rho,exgcd)

    Description 一种非对称加密算法的密钥生成过程如下: 1. 任选两个不同的质数 p ,q 2. 计算 N=pq , r=(p-1)(q-1) 3. 选取小于r ,且与 r 互质的整数 e  ...

  3. A NB群友 【记忆化搜索】(2019年华南理工大学程序设计竞赛(春季赛))

    冲鸭!去刷题:https://ac.nowcoder.com/acm/contest/625/A 题目描述 CC是著名的算法竞赛选手,他不仅人长得帅,而且技术了得,自然而然就有了许多粉丝. 为了能帮助 ...

  4. django用户验证机制

    django的验证机制 from django.contrib.auth.decorators import login_required 需要在要验证的界面添加`@login_required` 登 ...

  5. jenkins slave 挂载

    http://blog.sina.com.cn/s/blog_13cc013b50102wiau.html

  6. Spring整合MyBatis(三)sqlSessionFactory创建

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.SqlSessionFactoryBean的初始化 二.获取 ...

  7. Mac环境下安装配置Hadoop伪分布式

    伪分布式需要修改5个配置文件(hadoop2.x的配置文件$HADOOP_HOME/etc/hadoop) 第一个:hadoop-env.sh #vim hadoop-env.sh #第25行,由于新 ...

  8. grep 搜索多个同时满足的条件

    (二) Grep AND 操作 1. 使用 -E 'pattern1.*pattern2' grep命令本身不提供AND功能.但是,使用 -E 选项可以实现AND操作.   grep -E 'patt ...

  9. 聊聊并发——深入分析ConcurrentHashMap

    术语定义 术语 英文 解释 哈希算法 hash algorithm 是一种将任意内容的输入转换成相同长度输出的加密方式,其输出被称为哈希值. 哈希表 hash table 根据设定的哈希函数H(key ...

  10. C语言学习记录_2019.02.05

    switch只能判断整数,而分段函数的判别是一个范围,我们无法用整数来表示范围 跟踪语句的方法: (1)debug调试 (2)printf( )语句跟踪 小套路:当循环次数很大时,可以先模拟较小次数的 ...