从零系列--node爬虫利用进程池写数据
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爬虫利用进程池写数据的更多相关文章
- python系列之 - 并发编程(进程池,线程池,协程)
需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...
- Python之进程 3 - 进程池和multiprocess.Poll
一.为什么要有进程池? 在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务.那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗 ...
- (7)Pool进程池
(1)# 开启过多的进程并不一定提高你的效率 因为进程池可以实现并行的概念,比Process单核并发的速度要快 # 如果cpu负载任务过多,平均单个任务执行的效率就会低,反而降低执行速度. 1个人做4 ...
- python基础-UDP、进程、进程池、paramike模块
1 基于UDP套接字1.1 介绍 udp是无连接的,是数据报协议,先启动哪端都不会报错 udp服务端 import socket sk = socket() #创建一个服务器的套接字 sk.bind( ...
- 运用pool进程池启动大量子进程
# Pool进程池类 from multiprocessing import Pool import os import time import random def run(index): prin ...
- 进程池(Pool)
进程池用于进程维护, 当使用时,将会去进程池取数据 from multiprocessing import Pool, Processimport os, time def f(i): time.sl ...
- python爬虫之线程池和进程池
一.需求 最近准备爬取某电商网站的数据,先不考虑代理.分布式,先说效率问题(当然你要是请求的太快就会被封掉,亲测,400个请求过去,服务器直接拒绝连接,心碎),步入正题.一般情况下小白的我们第一个想到 ...
- python编程系列---进程池的优越性体验
1.通过multiprocessing.Process()类创建子进程 import multiprocessing, time, os, random def work(index): " ...
- 进程池与回调函数与正则表达式和re爬虫例子
# 使用进程池的进程爬取网页内容,使用回调函数处理数据,用到了正则表达式和re模块 import re from urllib.request import urlopen from multipro ...
随机推荐
- 多线程之Timer和TimerTask
Timer是一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask.TimerTask是一个抽象类,实现了Runnabl ...
- 【转】python中的对象拷贝
转自:https://www.cnblogs.com/bhlsheji/p/5352330.html python中.进行函数參数传递或者返回值时,假设是一般的变量,会拷贝传递.假设是列表或字典则是引 ...
- js对LocalDateTime时间的格式化成yyyy-MM-dd HH:mm:ss
formatter: function(value,row,index){ var arr = value; if(arr==null || arr==""){ return &q ...
- CommonJS、AMD、CMD、NodeJs、RequireJS到底有什么联系?
JS中的模块规范(CommonJS,AMD,CMD),如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范,本文包括这三个规范的来源及对应的产物的原理. 一.C ...
- IntelliJ IDEA使用技巧整理
1 .写代码时用 Alt-Insert ( Code|Generate… )可以创建类里面任何字段的 getter 与 setter 方法. 2 .右键点击断点标记(在文本的左边栏里)激活速查菜单,你 ...
- ZOJ 3212 K-Nice(满足某个要求的矩阵构造)
H - K-Nice Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu Submit Sta ...
- Tensorflow-slim 学习笔记(二)第一层目录代码解读
通过阅读代码来学习,一向时最直接快速的.本章将讲解slim的第一层目录tensorflow/tensorflow/contrib/slim/python/slim的代码. 本层代码主要包括learni ...
- .Net文档下载
public static void DownLoadFile(string fileName, HttpResponse Response, HttpServerUtility Server) { ...
- Liunx信息显示与文件搜索
. uname 显示系统相关信息,如内核版本号,硬件架构 -a # 显示系统所有相关信息 -m # 显示计算机硬件架构 -n # 显示主机名称 -r # 显示内核发行版本号 -s # 显示内核名称 - ...
- GATK--数据预处理,质控,检测变异
版权声明:本文源自 解螺旋的矿工, 由 XP 整理发表,共 13781 字. 转载请注明:从零开始完整学习全基因组测序(WGS)数据分析:第4节 构建WGS主流程 | Public Library o ...