用Node.js爬取免费代理

背景

在极客学院的微信公众号上看到了一个Node.js写爬虫的入门教程——用nodejs去爬一下A站老司机的文章,感觉挺有意思,于是动手写一下。

又想起有位大神用python写过一个抓免费代理的爬虫,于是模仿一下,用nodejs来实现。

依赖库

  • request:发请求,下载网页用的,类似于python的urllib2
  • cheerio:解析网页用的,语法和jquery相似,类似于python的beautifulsoup。

直接用npm下载即可

1
2
npm install request --save
npm install cheerio --save

程序功能

从百度到的提供免费代理的网站上爬取免费代理,并通过访问静态资源的方式检测代理是否可用,将可用的代理存放到本地文件当中。

与python的不同

用python写过不少爬虫,本来以为这次会非常轻松的完成,不过失算了。

由于nodejs的单线程异步特性,如果不加思考直接像python那么写,那么request请求还没回来的时候下面的代码就已经执行完了,保存的总是空的。

所以得做一些小手脚让它等待异步函数执行完毕再运行剩下的代码。我采用的办法是用标志量。

更好的解决办法应该是用promise,不过我比较愚鲁,看了半天愣是没看懂,希望不久的将来能领悟吧……

代码

放github上了https://github.com/kongtianyi/freeProxySpider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
var request = require("request");
var cheerio = require("cheerio");
var fs = require("fs");

var proxys = []; //保存从网站上获取到的代理
var useful = []; //保存检查过有效性的代理


/**
* 获取www.xicidaili.com提供的免费代理
*/
function getXici() {
url = "http://www.xicidaili.com/nn"; // 国内高匿代理

request ({
url: url,
method: "GET",
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36'
} //给个浏览器头,不然网站拒绝访问
}, function(error, response, body) {
if(!error) {
var $ = cheerio.load(body);
var trs = $("#ip_list tr");
for(var i=1;i<trs.length;i++) {
var proxy = {};
tr = trs.eq(i);
tds = tr.children("td");
proxy['ip'] = tds.eq(1).text();
proxy['port'] = tds.eq(2).text();
var speed = tds.eq(6).children("div").attr("title");
speed = speed.substring(0, speed.length-1);
var connectTime = tds.eq(7).children("div").attr("title");
connectTime = connectTime.substring(0, connectTime.length-1);
if(speed <= 5 && connectTime <= 1) { //用速度和连接时间筛选一轮
proxys.push(proxy);
}
}
}
check();
});
}

/**
* 过滤无效的代理
*/
function check() {
//尝试请求百度的静态资源公共库中的jquery文件
var url = "http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js";
var flag = proxys.length; //检查是否所有异步函数都执行完的标志量
for(var i=0;i<proxys.length;i++) {
var proxy = proxys[i];
request({
url: url,
proxy: "http://" + proxy['ip'] + ":" + proxy['port'],
method: 'GET',
timeout: 20000 //20s没有返回则视为代理不行
}, function (error, response, body) {
if(!error) {
if (response.statusCode == 200) {
//这里因为nodejs的异步特性,不能push(proxy),那样会存的都是最后一个
useful.push(response.request['proxy']['href']);
console.log(response.request['proxy']['href'], "useful!");
} else {
console.log(response.request['proxy']['href'], "failed!");
}
} else {
//console.log("One proxy failed!");
}
flag--;
if (flag == 0) {
saveProxys();
}
});
}
}

/**
* 把获取到的有用的代理保存成json文件,以便在别处使用
*/
function saveProxys() {
fs.writeFileSync("proxys.json", JSON.stringify(useful));
console.log("Save finished!");
}

getXici(); //启动这个爬虫
有钱的捧个钱场~