• nodejs抓取别人家的页面的始末


    内容:分析并获取页面调取数据的API(接口),并跨域获取数据保存在文档中(nodejs做代理-CORS)


    事由以及动机

    2015年9月份全国研究生数学建模竞赛的F题,旅游线路规划问题。其中需要自己去查很多数据。例如所给201个5A级景区的位置,以及景区距离所在省会距离等等~开始队友小伙伴准备从百度手动去一个一个查询,但是效率极低,在这么短的时间内,需要收集这么多数据是多么的耗时,并且也不能把大把时间花费在查资料上,虽然说查资料是必须的,题目也鼓励我们从网上查询相关数据,因此在团队中的我就想到了让计算机帮我们去做这件事。

    第一步,确定想要抓取的信息,获取数据服务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来调取他人的服务了

     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+'
    ');
    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+'
    ');

    允许所有用户跨域访问,因此我们就能访问自己搭建的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次的限制。

  • 相关阅读:
    Java
    一个web项目web.xml的配置中<context-param>配置作用
    JVM之几种垃圾收集器简单介绍
    JVM日志和参数的理解
    Java GC日志查看
    Java-性能调优-理解GC日志
    理解Java的GC日志
    tomcat打印GC日志
    快速解读GC日志
    Java 堆内存
  • 原文地址:https://www.cnblogs.com/alvinwei1024/p/4834045.html
Copyright © 2020-2023  润新知