zoukankan      html  css  js  c++  java
  • 零基础掌握百度地图兴趣点获取POI爬虫(python语言爬取)(进阶篇)

    好,现在进入进阶篇教程。 
    1.获取昆明市的bounds值 
    看到下面这个东西了吧?在文本框里写入昆明市,或者其他的行政区划地名,北京市、朝阳区、大河沟子村什么的。 
    这也是通过调用百度地图开放平台API实现的。 

    实现起来很简单,把下面这段代码复制到一个txt文件中,然后把txt文件的拓展名改成html,用浏览器打开,就可以查询行政区划的范围了。

    <!DOCTYPE html>  
    <html>  
    <head>  
        <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />  
        <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />  
        <style type="text/css">  
            body, html,#allmap { 100%;height: 100%;overflow: hidden;margin:0;font-family:"微软雅黑";}  
            #panel{  
                position:absolute;  
                left:5px;  
                top:5px;  
            }  
            #result{  
                background: #fff;  
                padding:5px;  
            }  
        </style>  
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>  
        <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ"></script>  
        <title>添加行政区划</title>  
    </head>  
    <body>  
        <div id="allmap"></div>  
        <div id="panel">  
            <div>  
            <input type="text" id="keyword" value="昆明市"/>  
            <input type="button" value="查看范围" id="commitBtn"/>  
            边界经纬度坐标  
            <textarea id="pathStr"></textarea>  
            边界墨卡托坐标  
            <textarea id="pathMc"></textarea>  
            </div>  
            <div id="result">  
            </div>  
        </div>  
    </body>  
    </html>  
    <script type="text/javascript">  
        // 百度地图API功能  
        var map = new BMap.Map("allmap");  
        map.centerAndZoom(new BMap.Point(116.403765, 39.914850), 5);  
        map.enableScrollWheelZoom();  
        var mercatorProjection = map.getMapType().getProjection();  
        $("#commitBtn").bind('click', function(){  
            getBoundary($("#keyword").val());  
        });  
        function getBoundary(city){         
            var bdary = new BMap.Boundary();  
            bdary.get(city, function(rs){       //获取行政区域  
                map.clearOverlays();        //清除地图覆盖物         
                var count = rs.boundaries.length; //行政区域的点有多少个  
                if (count === 0) {  
                    alert('未能获取当前输入行政区域');  
                    return ;  
                }  
                var pointArray = [];  
                for (var i = 0; i < count; i++) {  
                    var ply = new BMap.Polygon(rs.boundaries[i], {strokeWeight: 2, strokeColor: "#ff0000"}); //建立多边形覆盖物  
                    map.addOverlay(ply);  //添加覆盖物  
                    pointArray = pointArray.concat(ply.getPath());  
                }      
                var pathStr = "";  
                var pathMc = "";  
                for (var i = 0; i < pointArray.length; i++) {  
    
                    var mc = mercatorProjection.lngLatToPoint(pointArray[i]);  
                    pathStr += pointArray[i].lng + "," + pointArray[i].lat + ";";  
                    pathMc += mc.x + "," + mc.y + ";";  
                }  
                $('#pathStr').html(pathStr);  
                $('#pathMc').html(pathMc);  
                var ply = new BMap.Polygon(pointArray , {strokeWeight: 2, strokeColor: "#ff0000"}); //建立多边形覆盖物  
                var bounds = ply.getBounds();  
                var ne = bounds.getNorthEast();  
                var sw = bounds.getSouthWest();  
                var neMc = mercatorProjection.lngLatToPoint(ne);  
                var swMc = mercatorProjection.lngLatToPoint(sw);  
                var str = "经纬度:左下角,右上角:" + sw.lng + "," + sw.lat + ";" + ne.lng + "," + ne.lat  
                                                     + "<br/>墨卡托坐标:左下角,右上角:" + swMc.x + "," + swMc.y + ";" + neMc.x + "," + neMc.y;  
                $('#result').html(str);  
                console.log(bounds);  
                map.setViewport(pointArray);    //调整视野                   
            });     
        }  
        //getBoundary('北京');  
    </script>

    HTML是一个很神奇的格式,代码可以在文本文档里写,不过应该很少有人用文本文档写代码吧。 
    这段代码可以直接拿来用,也是我从网上找的,就不分析了。

    2.更合理的对查询范围进行切分。 
    这是一个很常见的问题,我们要采集昆明市的中学兴趣点,然后就把矩形等分了六份,遍历一遍(其实要不遗漏的获取兴趣点,只切六个绝对不够用)。 
    这种切分方式其实并不完美,分析一下,中心城区兴趣点肯定分布更密集,而郊区会稀疏一些,而且一个城市的边界不可能是矩形的,我们用一个大矩形切分,会爬取到一些其他城市的兴趣点。 
    有相关从业经验的人应该能想到,如果有这个城市的分幅格网,遍历分幅格网来爬取兴趣点会更好一些,当然分幅格网我们也可以自己生成,根据预估的兴趣点疏密程度,中心城区格网加密一些,外围合并一些。 
    arcgis有一个工具fishnet(创建渔网),可以生成格网。 
    四至坐标可以在字段计算器里计算,选用python语言

    minX=!shape.extent.xmin!
    maxX=!shape.extent.xmax!
    minY=!shape.extent.ymin!
    maxY=!shape.extent.ymax!

    之前写过一篇画分幅格网的教程:http://blog.sina.com.cn/s/blog_4c6ee7230102v590.html

    把arcgis属性表导出,可以用excel打开。 
    用这个坐标列表去生成url列表,主要就是open和write语句的运用,其实都可以直接在excel里用函数去生成url列表。 
    python逐行读入:

    f=open(路径,’a’)
    f.readlines()

    3.python中文乱码问题解决 
    其实这是一个很棘手的问题。对于初学者来说,遇到乱码问题,如何解决是一个幸运度的问题。有可能运气不好,就解决不了了,有可能运气够好,根本遇不上。 
    在乱码问题上,python2.7要多于python3 
    我精心挑选了几个我觉得讲得比较好的文章,大家可以参考一下,网上相关的文章太多了,容易懵。 
    这篇中文乱码的解决方式: 
    http://www.jb51.net/article/42707.htm 
    用sys.getfilesystemencoding()获取文件系统的编码方式。

    import sys
    type = sys.getfilesystemencoding()
    print mystr.decode('utf-8').encode(type)

    这篇文章写得比较细: 
    http://blog.csdn.net/ggggiqnypgjg/article/details/53271541

    我的经验是,如果遇到乱码,怎么都调试不成功,那么可以换一个编译环境,从python2.7换到python3,或者用别的函数,例如不用urllib2,用beautiful soul,或者requests等,有可能莫名其妙乱码的问题就不出现了呢!

    4.并发量限制与延时功能

    import time
    time.sleep(10)

    这两行代码的意思是,延时10秒中,它解决的是一分钟内并发量限制的问题,如果我们没有做认证,那么一分钟能访问API服务的次数不超过几次,超过了就会提示访问超过并发量,就爬不到数据了。 
    解决这个问题的方法就是用time.sleep(10),每次循环都先休眠10秒,就不会访问超过并发量了。 
    我觉得10秒够用了,所以就设定了10秒,不过如果认证过的开发者,应该不会遇到并发量限制的问题。 
    这段代码示例一下:

    import time
    time.sleep(10)
    print time.time()

    休眠十秒,打印当前时间,结果是一个浮点秒数。 
    5.把代码移植到python3中。 
    python2.7和python3略微有些差异,python3版本有一个好处就是中文乱码的情况没那么多,而且很多功能和第三方库都被整合了。 
    下面这段代码是python3中的,可以看出比较于python2.7版本,进行了几处改变,requests、webbrowser、列表的引用等。

    #-*-coding:UTF-8-*- 
    import json
    import sys
    import requests  #导入requests库,这是一个第三方库,把网页上的内容爬下来用的
    ty=sys.getfilesystemencoding()  #这个可以获取文件系统的编码形式
    import time
    lat_1=24.390894
    lon_1=102.174112
    lat_2=26.548645
    lon_2=103.678942   #坐标范围
    las=1  #给las一个值1
    ak='9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO'
    push=r'D:pythonzwzwlast.txt'
    #我们把变量都放在前面,后面就不涉及到变量了,如果要爬取别的POI,修改这几个变量就可以了,不用改代码了。
    
    
    print (time.time())  #相较于python2.7,,python3print 需要加括号。
    print ('开始')
    urls=[] 声明一个数组列表
    lat_count=int((lat_2-lat_1)/las+1)
    lon_count=int((lon_2-lon_1)/las+1)
    for lat_c in range(0,lat_count):
        lat_b1=lat_1+las*lat_c
        for lon_c in range(0,lon_count):
            lon_b1=lon_1+las*lon_c
            for i in range(0,20):
                page_num=str(i)
                url='http://api.map.baidu.com/place/v2/search?query=中学& bounds='+str(lat_b1)+','+str(lon_b1)+','+str(lat_b1+las)+','+str(lon_b1+las)+'&page_size=20&page_num='+str(page_num)+'&output=json&ak='+ak
                urls.append(url)
    #urls.append(url)的意思是,将url添加入urls这个列表中。
    
    f=open(r'D:pythonkunmingxuexiao.txt','a',encoding='utf-8')
    
    print ('url列表读取完成')
    
    for url in urls:
        time.sleep(10) #为了防止并发量报警,设置了一个10秒的休眠。
        html=requests.get(url)#获取网页信息
        data=html.json()#获取网页信息的json格式数据
        for item in data['results']:
            jname=item['name']
            jlat=item['location']['lat']
            jlon=item['location']['lng']
            jadd=item['address']
            j_str=jname+','+str(jlat)+','+str(jlon)+','+jadd+'
    '
            f.write(j_str)
        print (time.time())
    f.close()
    print ('完成')    

    6.代码简化问题。 
    可以通过分析json数据提炼一下简化方式。 
    网页打开之后,看一下。 

    “status”:0, 
    “message”:”ok”, 
    “total”:400, 
    “results”:[ 

    “name”:”北大附中云南实验学校”, 
    “location”:{ 
    “lat”:25.009573, 
    “lng”:102.723208 
    }, 
    “address”:”昆明市日新中路北大附中云南实验学校”, 
    “street_id”:”beabdbf4ac3394997069d3c7”, 
    “detail”:1, 
    “uid”:”beabdbf4ac3394997069d3c7” 
    主要看results上面那三行,其中total,是这个矩形范围内有多少个兴趣点,有400个,说明我矩形画大了,应该再细分一下,这个数应该小于400,因为我们之前已经说过20页网址最多爬400个poi,total是400,说明实际的poi数量是大于400个的。 
    提取某一坐标范围中第一页数据的时候,我们可以先获取total值,这样就可以计算出page_num的值了,如果total是100,那么只循环到第五页,page_num=4的时候就可以了。 
    这是代码的一个简化方式。 
    当然应该还有很多,有待我们发觉。

    7.过程参考资料汇总 
    因为使用python的人很多,所以网上的资料也很多,不过要找到比较合适的,也没那么容易。但是说实话,走弯路、排除错误答案也是学习收获的一个过程,实践过错的,才知道什么是对的嘛! 
    最有用的参考资料,应该是还算是官网。 
    https://www.python.org/ 
    学好英语很必要。 
    这个网址,讲的是requests的用法。 
    http://docs.python-requests.org/zh_CN/latest/user/quickstart.html 
    当然,买本书应该也不错。 
    然后脚本之家和CSDN都有很好的教程,不过也不是所有教程都是对的,多看多试多思考多练习,就会有多获得。 
    最后会再来一篇python安装和第三方库安装篇,这个python的零基础教程就先告一段落吧!

    转自----------------http://blog.csdn.net/sinat_41310868/article/details/78746251

  • 相关阅读:
    Android ANR异常解决方案
    数据结构之斐波那契查找
    数据结构之插值查找
    数据结构之折半查找
    Android Task 任务
    java中“==”号的运用
    php中向前台js中传送一个二维数组
    array_unique和array_flip 实现去重间的区别
    js new Date() 获取时间
    手机端html5触屏事件(touch事件)
  • 原文地址:https://www.cnblogs.com/lilinpging/p/8202940.html
Copyright © 2011-2022 走看看