研究使用nodejs抓取网页信息及应用

万智牌已经弃坑了快四年了,现在每次大学聚会的时候大家说打几把牌,而这种频率每年也就一两次,实在是没必要用实体的了。所幸有magiccards.info这个网站,他提供了一个功能,可以生成所选卡图的页面,然后可以直接去外面打印这个页面,打印的效果也非常不错,但根据牌表一张一张去加,实在是有点精污,于是想到可以使用代码来解决一下这个问题。

目前想到的流程是:

  • 准备好牌表的文本文件
  • 服务器接收一下文件,读取每一行的卡牌名称,然后去magiccards获取这张牌的系列编码和id
  • 回传给页面后,由页面来访问magiccards的卡图接口,由页面来做这个事是因为这个应该是记录在cookie里的,不能由服务器访问,不然最后的结果页面看不到

服务端

服务端只需要做一个页面,和一个接口就可以。因为整体使用了co的方式,所以读取文件这里,使用了co-fs插件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let
input = yield fs.readFile(req.file.path, 'utf8'),
cards = [],
line = "";
for(let i = 0, len = input.length; i < len; i++){
let
tmp = "",
chari = input[i];
if(chari == "\n"){
tmp = yield webReader.read(line);
cards.push(tmp);
(async function(){
await sleep(200);
})();
line = "";
}else{
line += chari;
}
}
console.log("all done");
return {error: 0, data: cards};
function sleep(ms){
return new Promise(resolve => setTimeout(resolve, ms))
}

其中webReader这个对象是自己写的模块,主要完成根据这一行的卡牌名称,抓取网页信息,获得系列编码和id。每次抓取之间加了200ms的间隔。

webReader这个模块中,主要使用了cheerio这个插件,然后还需要转一下编码。

1
2
let superagent = require("superagent");
require('superagent-charset')(superagent);

根据卡牌的名称,去抓取这张卡牌的搜索页面中,对应的卡牌系列编码和id,返回即可。cheerio这个插件的使用类似于jquery,通过研究页面的结构,层层递进,直到把需要的数据拿到为止。
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
const
logger = require("log4js").getLogger("webReader.js"),
co = require('co'),
$ = require('cheerio'),
browserMsg = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
'Content-Type': 'application/x-www-form-urlencoded'
},
BASE_URL = "https://magiccards.info/";
module.exports.read = function(txt){
return co(function *(){
let
cookie = {
},
geturl = BASE_URL + "query";
geturl = getAllUrlAddress(geturl, txt);
var httpres = yield superagent
.get(geturl)
.set("Cookie", cookie)
.set(browserMsg)
.charset("utf-8");

let
htmlbody = $.load(httpres.text),
tmp = htmlbody("html").find("table").eq(3).find("td").eq(1).find("span").eq(0).find("a").eq(0);

return tmp[0].attribs.href;
}).then(function(result){
return result;
}).catch(function(error){
logger.error(error);
});
};
function getAllUrlAddress(url, str){
url += "?";
str = myTrim(str);
let idx = str.indexOf(" ");
str = str.substring(idx + 1);
str = str.replace(/\s/g, "+");
return url + "q=" + str;
}

返回到页面后,拿到的是卡牌的数组,依次去访问网站的添加页面即可。