nodejs写的一个网页爬虫例子(坏链率)
因为工作需要,用nodejs写了个简单的爬虫例子,之前也没用过nodejs,连搭环境加写大概用了5天左右,so。。。要多简陋有多简陋,放这里给以后的自己看~~
整体需求是:给一个有效的URL地址,返回该网页上所有无效链接的百分比(坏链率)
第一个文件:计算环链率 urlSpider.js
/*================================================
@author MissUU
链接抓取思路: 1. 获取页面内容
2. 正则取得所有<a>
3. 进一步取得href属性值,如果首位是“则剔除,不是http开头加上域名(javascript开头除外)
4.正则验证是否是常见URL格式
================================================*/
var http = require('http');
var async = require('async');
var dbHandle = require('./dbHandle.js'); //主程序
var runUrlSpider = function(obj, callback){
//10s timeout
var request_timer = setTimeout(function() {
req.abort();
console.log('Request Timeout.');
}, 10000); var urlBadLink = new UrlBadLink();
var html='';
var req = http.get(obj.url, function(res) { clearTimeout(request_timer); res.setEncoding('utf8');
res.on('data', function (chunk) {
html += chunk;
}).on('end', function(){
console.log('*******开始提取有效链接地址******');
console.log(new Date().toLocaleString());
console.log(obj.url);
urlBadLink.host = obj.url;
urlBadLink.id = obj.id;
matchURL(html, urlBadLink, function(){
callback();
});
});
}); req.on('error', function(e) {
console.log('problem with request: ' + e.message);
callback();
});
} //this is the entrance of code
var main = function(){
var urlArray = dbHandle.showUrls(1, function(result){
async.eachSeries(result, runUrlSpider, function(err){
console.log('******this is the end, haha*******');
});
});
// console.log(urlArray); }; main(); /*
* 用于异步放送get请求
*
* @param {string} content 原始页面信息
* @param {string} host 主域名
*/
function matchURL(content, urlBadLink, callend){
var host = urlBadLink.host;
var anchor = /<a\s[^>]*>/g;
var matches = content.match(anchor);
var badLink = 0;
var flag = 0;
var HttpGet = function(url,callback){
//10s timeout
var request_timer = setTimeout(function() {
req.abort();
console.log('Request Timeout.');
}, 10000); var req = http.get(url, function(res) {
clearTimeout(request_timer); res.on('data', function () {
}).on('end', function(){
console.log(++flag + ": " + url + ' response status: ' + res.statusCode); if(!(res.statusCode >= 200 && res.statusCode < 400)){
console.log('-----------------------');
badLink++;
} callback();
});
});
req.on('error', function(err){
console.log(++flag + ": " + 'problem with request: ' + err.message);
badLink++;
callback();
});
}; var urls = filterUrl(matches,host); if(urls !== null){
var totalLink = urls.length;
//console.log(urls);
async.eachSeries(urls, HttpGet, function(err){
// var urlBadLink = new UrlBadLink(host,totalLink, badLink);
// console.log("坏链个数为: " + urlBadLink.badCounts);
// console.log("坏链率为: " + urlBadLink.getRate());
urlBadLink.total = totalLink;
urlBadLink.badCounts = badLink;
//data store puts here
dbHandle.updateBadLink(urlBadLink);
callend();
});
}else{
console.log('no links found');
urlBadLink.total = 10;
urlBadLink.badCounts = 0;
dbHandle.updateBadLink(urlBadLink);
callend();
}
} //正则取得href属性值
function URLFommat(strUrl,host){ var urlPatten = /href=[\'\"]?([^\'\"]*)[\'\"]?/i;
var temp = urlPatten.exec(strUrl); if(temp!= null){
var url = temp[0].substring(6,temp[0].length-1).trim(); if(url.indexOf("\"") != -1){
url = url.slice(url.indexOf("\"") + 1);
} if(url.charAt(0) == "/"){
url = url.slice(1);
return host + url;
}else if((url.indexOf("http") == -1)&&
(url.indexOf("javascript") == -1)){
return host + url;
}else
return url;
}else
return null;
} //test URLFommat
//var test = "http://baidu.com";
// var test1 = " \"http://baidu.com";
//var test2 = "/wenhao";
//console.log(URLFommat(test,"www.sina.com.cn"));
//console.log(URLFommat(test1,"www.sina.com.cn"));
//console.log(URLFommat(test2,"www.sina.com.cn")); //测试是否为常见url格式
function IsURL(strUrl) {
if(strUrl != null){
var regular = /^\b(((http?|ftp):\/\/)?[-a-z0-9]+(\.[-a-z0-9]+)*\.(?:com|edu|gov|int|mil|net|org|biz|info|name|museum|asia|coop|aero|[a-z][a-z]|((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]\d)|\d))\b(\/[-a-z0-9_:\@&?=+,.!\/~%\$]*)?)$/i;
if (regular.test(strUrl)) {
return true;
}
else {
return false;
}
}else
return false;
} //对象
function UrlBadLink(id, host, total, badCounts){
this.id = id;
this.host = host;
this.total = total;
this.badCounts = badCounts; if(typeof this.getRate != "function"){
UrlBadLink.prototype.getRate = function(){
var output = Number(Math.round(this.badCounts/this.total*10000)/100).toFixed(2)+'%';
return output;
};
}
} function filterUrl(arr,host){ if(arr === null)
return null;
var output = [];
arr.forEach(function(item,index,array){
//console.log(item);
var formatURL = URLFommat(item,host); if(IsURL(formatURL)){
output.push(formatURL);
}//if
});//forEach return output;
}
第二个文件:将数据存库,dbHandle.js
/**
* @author MissUU
* @des MySql基本操作
* API: https://github.com/felixge/node-mysql
*/ var mysql = require('mysql'); mysql.createConnection('mysql://root:apple@localhost/test?debug=false'); var pool = mysql.createPool({
host : '10.102.1.00',
user : 'root',
password : 'root',
database : 'test',
connectionLimit: 15
}); //读取urls
exports.showUrls = function (groupId, callback){ console.log('this is showUrl()');
pool.getConnection(function(err, conn){ if (err) {
console.log("connection error!");
console.log(err);
} conn.query('SELECT id,realurl as url FROM t_site WHERE siteGroupId = ?',groupId, function(err, result){
if(err){
console.log(err.message);
} conn.release();
if(result.length){
// console.log(result instanceof Array);
callback(result);
return true;
}else{
callback('');
return false;
}
});
});
}; exports.updateBadLink = function (urlBadLink){
//若不含数据则不插入
if (!!urlBadLink) { pool.getConnection(function(err, conn){ if (err) {
console.log("connection error!");
console.log(err);
} var updateSql = "UPDATE a_qualityinfo SET brokenRate = '"+ urlBadLink.getRate() +"' WHERE siteId = " + urlBadLink.id; console.log(updateSql); conn.query(updateSql, function(err, result){
if(err){
console.log(err.message);
console.log('update fail');
} conn.release();
console.log('update success');
});// conn.query
});//pool.getConnection
}
};
代码后期还会改动,这里有几点需要注意的:
1、http.get有时会一直等待响应,所以一定要判断下,超时则认为出错,要不程序就卡住了。。。= =!
2、注意callback的使用,要不然很难规范执行顺序的,用过nodejs的都懂得。。。
nodejs写的一个网页爬虫例子(坏链率)的更多相关文章
- 用go iris 写的一个网页版文件共享应用(webapp)
主要演示文件拖拽上传或点击上传到不同的目录中,提供下载和删除功能. 目录结构: -main.go --share(用于分类存放上传文件的目录) --v(视图目录) ---share.html main ...
- 用Python写一个小爬虫吧!
学习了一段时间的web前端,感觉有点看不清前进的方向,于是就写了一个小爬虫,爬了51job上前端相关的岗位,看看招聘方对技术方面的需求,再有针对性的学习. 我在此之前接触过Python,也写过一些小脚 ...
- Jmeter_ForEach控制器实现网页爬虫
一直以来,爬虫似乎都是写代码去实现的,今天像大家介绍一下Jmeter如何实现一个网页爬虫! Jmeter的爬虫原理其实很简单,就是对网页提交一个请求,然后把返回的所有href提取出来,利用ForEac ...
- Jmeter(十九)_ForEach控制器实现网页爬虫
一直以来,爬虫似乎都是写代码去实现的,今天像大家介绍一下Jmeter如何实现一个网页爬虫! 龙渊阁测试开发家园 317765580 Jmeter的爬虫原理其实很简单,就是对网页提交一个请求,然后把返回 ...
- c#网页爬虫初探
一个简单的网页爬虫例子! html代码: <head runat="server"> <title>c#爬网</title> </head ...
- 网页爬虫的设计与实现(Java版)
网页爬虫的设计与实现(Java版) 最近为了练手而且对网页爬虫也挺感兴趣,决定自己写一个网页爬虫程序. 首先看看爬虫都应该有哪些功能. 内容来自(http://www.ibm.com/deve ...
- 网页抓取:PHP实现网页爬虫方式小结
来源:http://www.ido321.com/1158.html 抓取某一个网页中的内容,需要对DOM树进行解析,找到指定节点后,再抓取我们需要的内容,过程有点繁琐.LZ总结了几种常用的.易于实现 ...
- Python网页爬虫(一)
很多时候我们想要获得网站的数据,但是网站并没有提供相应的API调用,这时候应该怎么办呢?还有的时候我们需要模拟人的一些行为,例如点击网页上的按钮等,又有什么好的解决方法吗?这些正是python和网页爬 ...
- PHP实现网页爬虫
抓取某一个网页中的内容,需要对DOM树进行解析,找到指定节点后,再抓取我们需要的内容,过程有点繁琐.LZ总结了几种常用的.易于实现的网页抓取方式,如果熟悉JQuery选择器,这几种框架会相当简单. 一 ...
随机推荐
- VC error LNK2005 解决办法
error LNK2005: "int __cdecl VerifyVMR9(void)" (?VerifyVMR9@@YAHXZ) 解决办法 在 属性->配置属性-> ...
- netty是什么?
Netty是什么? 相对于Tomcat这种Web Server(顾名思义主要是提供Web协议相关的服务的),Netty是一个Network Server,是处于Web Server更下层的网络框架,也 ...
- C#基础练习(事件登陆案例)
Form1的后台代码: namespace _08事件登陆案例 { public partial class Form1 : Form { public Form1() ...
- sql中exists,not exists的用法
exists : 强调的是是否返回结果集,不要求知道返回什么, 比如: select name from student where sex = 'm' and mark exists(select ...
- List应用举例
1.集合的嵌套遍历 学生类: package listexercise; /** * Created by gao on 15-12-9. */ public class Student { priv ...
- spring cloud config 入门
简介 Spring cloud config 分为两部分 server client config-server 配置服务端,服务管理配置信息 config-client 客户端,客户端调用serve ...
- LA 6187 - Never Wait for Weights 并查集的带权路径压缩
只有一个地方需要注意: 设节点a的根为u,b的跟为v,则:a = u + d[a]; b = v + d[b]; 已知:b-a=w.所以v - u = d[a] - d[b] + w; 在合并两个集 ...
- 简单的SocketExample
客户端//---------------VerySimpleClient.java package SocketExample; // Tue Nov 2 18:34:53 EST 2004 // / ...
- WCF-学习笔记概述之计算服务(1)
关于WCF的介绍,在此不再赘述,其他地方应有尽有.直接开始实例,第一个实例以一个简单的计算服务为例,本人是学习了蒋金楠的<WCF全面解析>. 1.构建解决方案 Interface:用于定义 ...
- HDU3709 Balanced Number (数位dp)
Balanced Number Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Descript ...