内容:分析并获取页面调取数据的API(接口),并跨域获取数据保存在文档中(nodejs做代理-CORS)
事由以及动机
2015年9月份全国研究生数学建模竞赛的F题,旅游线路规划问题。其中需要自己去查很多数据。例如所给201个***级景区的位置,以及景区距离所 在省会距离等等~开始队友小伙伴准备从百度手动去一个一个查询,但是效率极低,在这么短的时间内,需要收集这么多数据是多么的耗时,并且也不能把大把时间 花费在查资料上,虽然说查资料是必须的,题目也鼓励我们从网上查询相关数据,因此在团队中的我就想到了让计算机帮我们去做这件事。
***步,确定想要抓取的信息,获取数据服务api
以查询个两地的行车时间为例,我们以百度地图为例,见下图
先打开需要去请求数据的网页,打开开发人员工具(我用的是chrome),选择Network选项卡,输入需要查询的内容(tips:先清除掉之前的网络获取纪录,以方便接下来的借接口分析)。
点击“查询”,并监控网络数据流,会发现网页发起了很多的http请求,并返回了结果。
通过分析所有请求,拿到想要的请求接口(一般情况下,都不会是Type为图片类型的,并且耗时较长的)。
点击某个请求时能看到该请求的详细信息
查看请求的头部信息Headers
拿到请求的地 址:requestURL,例如:http://map.baidu.com/?newmap=1&reqflag=pcmap& biz=1&pcevaname=pc2&da_par=direct&from=webmap&qt=nav&da_src=pcmappg.searchBox.button&c=289&sn=2$$$$$$%E4%B8%8A%E6%B5%B7%E5%B8%82$$0$$$$&en=2$$$$$$%E5%8C%97%E4%BA%AC%E5%B8%82$$0$$$$&sc=289&ec=289&rn=5&extinfo=63&tn=B_NORMAL_MAP&nn=0&ie=utf-8&l=12&b=(13503777.31,3639994.64;13542753.31,3642234.64)&t=1443022534161
并分析,一般我们要看的是URL中的querey部分,也就是?后面的内容,一般来说由很多(字母+百分号)构成的为中文字符,是汉字被url转码获得。可以把该地址拿到地址栏查询一下,汉字的内容
那我们的数据服务API就拿到了
编写数据访问页面
接下来就是利用XMLHTTPRequerst来调取他人的服务了
复制
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>getData</title> </head> <body> <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script> <script> var sn="北京市"; var en="上海市"; var url="http://map.baidu.com/?newmap=1&reqflag=pcmap&biz=1&pcevaname=pc2&da_par=direct&from=webmap&qt=nav&da_src=pcmappg.searchBox.button&c=289&sn=2$$$$$$"+ sn+"$$0$$$$&en=2$$$$$$"+ en+"$$0$$$$&sc=289&ec=289&rn=5&extinfo=63&tn=B_NORMAL_MAP&nn=0&ie=utf-8&l=12&b=(13503777.31,3639994.64;13542753.31,3642234.64)&t=1443022534161"; $.ajax({ url:url, type:"get", success:function(res){ console.log(res) }, error:function(e){ console.log(e) } }) </script> </body> </html> html
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.
运行察看结果:
跨域提示错误,跨域(见为什么浏览器不能跨域http://www.cnblogs.com/alvinwei1024/p/4626054.html)是浏览器的行为。
方法1: 通过jsonp的方法
复制
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>getData</title> </head> <body> <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script> <script> var sn="北京市"; var en="上海市"; var url="http://map.baidu.com/?newmap=1&reqflag=pcmap&biz=1&pcevaname=pc2&da_par=direct&from=webmap&qt=nav&da_src=pcmappg.searchBox.button&c=289&sn=2$$$$$$"+ sn+"$$0$$$$&en=2$$$$$$"+ en+"$$0$$$$&sc=289&ec=289&rn=5&extinfo=63&tn=B_NORMAL_MAP&nn=0&ie=utf-8&l=12&b=(13503777.31,3639994.64;13542753.31,3642234.64)&t=1443022534161"; $.ajax({ url:url, type:"get", dataType:"jsonp", jsonp:"callback", success:function(res){ console.log(res) }, error:function(e){ console.log(e) } }) </script> </body> </html> html
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.
运行结果:获取到想要的数据
可以拿到,北京到上海的距离1208548,时间48617以及距离等。
dis: 1208548
kps: Array[38]
rss: Array[38]
taxi: Object
time: 48617
toll: 580
#p#
方法二:CORS
除了方法以利用jsonp跨域外,还可以通过服务器做一个代理,通过cors绕过原来资源不允许跨域的限制。
本文利用node来做服务器,原因很简单,最方便,几句代码就能搞定,方便又快捷。
复制
var http = require('http'); var request_ = require('request'); var urlencode2=require("urlencode2"); var url=require('url') http.createServer(function (request, response) { var arg1 = url.parse(request.url, true).query; var sn=arg1.sn; var en=arg1.en; var req_url="http://api.map.baidu.com/?qt=nav&c=131&sn=2%24%24%24%24%24%24%20"+ urlencode2(sn,'gbk')+"%24%240%24%24%24%24&en=2%24%24%24%24%24%24"+ urlencode2(en,'gbk')+"%24%240%24%24%24%24&sy=0&ie=utf-8&oue=1&fromproduct=jsapi&res=api&callback=BMap._rd._cbk54249"; request_.get({ url:req_url, json:true }, function(error, response_, body) { if (!error && response_.statusCode == 200) { var res=-1; if(body){ res=body.split(',"toll":')[0];//time s res=res.split('"time":')[2]; console.log(res) if(!res){ res=-1; } else{ res=res/60; } } response.writeHead(200, { "Content-Type": "text/html; charset=UTF-8", 'Access-Control-Allow-Origin':request.headers.origin }); response.end(res+'\n'); } else{ // console.log(error) } } ) }).listen(8888); // 终端打印如下信息 console.log('Server running at http://127.0.0.1:8888/'); nodejs
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.
其中,本文用到了request(用于发起http请求)模块和urlencode2(主要用于URLEncode)模块
request安装:
npm install request
详见:https://github.com/request/request
urlencode2安装:
详见:https://github.com/node-modules/urlencode
1 var http = require('http');
2 http.createServer(function (request, response) {
3 //...
4 response.end('welcome baby');
5 }).listen(8888);
这几句简单的代码就搭建了一个web服务,端口号是8888
$ node 文件名.js
在终端输入以上指令即可允许该服务。
1 var arg1 = url.parse(request.url, true).query;
2 var sn=arg1.sn;
3 var en=arg1.en;
4 var req_url="http://api.map.baidu.com/?qt=nav&c=131&sn=2%24%24%24%24%24%24%20"+ 5 urlencode2(sn,'gbk')+"%24%240%24%24%24%24&en=2%24%24%24%24%24%24"+ 6 urlencode2(en,'gbk')+"%24%240%24%24%24%24&sy=0&ie=utf-8&oue=1&fromproduct=jsapi&res=api&callback=BMap._rd._cbk54249";
以上是获取查询参数并拼接请求字符串
然后利用request向目标服务器发送请求,并解析出需要的信息
最重要的是以下代码:
1 response.writeHead(200, {
2 "Content-Type": "text/html; charset=UTF-8", 3 'Access-Control-Allow-Origin':request.headers.origin 4 }); 5 response.end(res+'\n');
允许所有用户跨域访问,因此我们就能访问自己搭建的web服务了。
我在前端页面只需,请求我们的地址http://localhost:8888
并且指定sn(start node)与 en(end node)一并发送到服务器即可。
相关代码:https://github.com/AlvinWei1024/blog-resources/tree/master/20150923
作者:AlvinWei 文章出处:韦躐晟的博客 http://www.cnblogs.com/alvinwei1024/p/4834045.html