nodejs抓取別人家的頁面的始末

內容:分析並獲取頁面調取數據的API(接口),並跨域獲取數據保存在文檔中(nodejs作代理-CORS)html


事由以及動機前端

2015年9月份全國研究生數學建模競賽的F題,旅遊線路規劃問題。其中須要本身去查不少數據。例如所給201個5A級景區的位置,以及景區距離所在省會距離等等~開始隊友小夥伴準備從百度手動去一個一個查詢,可是效率極低,在這麼短的時間內,須要收集這麼多數據是多麼的耗時,而且也不能把大把時間花費在查資料上,雖說查資料是必須的,題目也鼓勵咱們從網上查詢相關數據,所以在團隊中的我就想到了讓計算機幫咱們去作這件事。node

第一步,肯定想要抓取的信息,獲取數據服務apijquery

以查詢個兩地的行車時間爲例,咱們以百度地圖爲例,見下圖git

先打開須要去請求數據的網頁,打開開發人員工具(我用的是chrome),選擇Network選項卡,輸入須要查詢的內容(tips:先清除掉以前的網絡獲取紀錄,以方便接下來的借接口分析)。github

點擊「查詢」,並監控網絡數據流,會發現網頁發起了不少的http請求,並返回告終果。web

 經過分析全部請求,拿到想要的請求接口(通常狀況下,都不會是Type爲圖片類型的,而且耗時較長的)。ajax

點擊某個請求時能看到該請求的詳細信息chrome

查看請求的頭部信息Headersnpm

拿到請求的地址: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來調取他人的服務了

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>getData</title>
 6 </head>
 7 <body>
 8     <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
 9     <script>
10         var sn="北京市";
11         var en="上海市";
12         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$$$$$$"+
13         sn+"$$0$$$$&en=2$$$$$$"+
14         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";
15 
16         $.ajax({
17             url:url,
18             type:"get",
19             success:function(res){
20                 console.log(res)
21             },
22             error:function(e){
23                 console.log(e)
24             }
25         })
26     </script>
27 </body>
28 </html>
html

運行察看結果:

跨域提示錯誤,跨域(見爲何瀏覽器不能跨域http://www.cnblogs.com/alvinwei1024/p/4626054.html)是瀏覽器的行爲。

方法1: 經過jsonp的方法

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>getData</title>
 6 </head>
 7 <body>
 8     <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
 9     <script>
10         var sn="北京市";
11         var en="上海市";
12         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$$$$$$"+
13         sn+"$$0$$$$&en=2$$$$$$"+
14         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";
15 
16         $.ajax({
17             url:url,
18             type:"get",
19             dataType:"jsonp",
20              jsonp:"callback",
21             success:function(res){
22                 console.log(res)
23             },
24             error:function(e){
25                 console.log(e)
26             }
27         })
28     </script>
29 </body>
30 </html>
html

運行結果:獲取到想要的數據

能夠拿到,北京到上海的距離1208548,時間48617以及距離等。

  1. dis1208548
  2. kpsArray[38]
  3. rssArray[38]
  4. taxiObject
  5. time48617
  6. toll580

 

 方法二:CORS

 除了方法以利用jsonp跨域外,還能夠經過服務器作一個代理,經過cors繞過原來資源不容許跨域的限制。

本文利用node來作服務器,緣由很簡單,最方便,幾句代碼就能搞定,方便又快捷。

 1 var http = require('http');
 2 var request_ = require('request');
 3 var urlencode2=require("urlencode2");
 4 var url=require('url')
 5 http.createServer(function (request, response) {
 6      var arg1 = url.parse(request.url, true).query; 
 7     var sn=arg1.sn;
 8     var en=arg1.en;
 9     var req_url="http://api.map.baidu.com/?qt=nav&c=131&sn=2%24%24%24%24%24%24%20"+
10           urlencode2(sn,'gbk')+"%24%240%24%24%24%24&en=2%24%24%24%24%24%24"+
11           urlencode2(en,'gbk')+"%24%240%24%24%24%24&sy=0&ie=utf-8&oue=1&fromproduct=jsapi&res=api&callback=BMap._rd._cbk54249";
12       request_.get({
13             url:req_url,
14             json:true
15         },
16         function(error, response_, body) {
17           if (!error && response_.statusCode == 200) {
18             var res=-1;
19             if(body){
20               res=body.split(',"toll":')[0];//time  s
21               res=res.split('"time":')[2];
22               console.log(res)
23               if(!res){
24                 res=-1;
25               }
26               else{
27                 res=res/60;
28               }
29             }
30             response.writeHead(200, {
31                 "Content-Type": "text/html; charset=UTF-8",
32                 'Access-Control-Allow-Origin':request.headers.origin
33             });
34             response.end(res+'\n');
35           }
36           else{
37             // console.log(error)
38           }
39         }
40     )
41 }).listen(8888);
42 // 終端打印以下信息
43 console.log('Server running at http://127.0.0.1:8888/');
nodejs

 其中,本文用到了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

本文版權歸做者和博客園共有,歡迎轉載

轉載請說明原文章出處

 

總結:

本文所用實例的百度地圖api無需這麼費勁去解析,可使用其公佈的公共API接口,可是天天的訪問次數有10w次的限制。

相關文章
相關標籤/搜索