python+高德API解决住房问题

1,项目来源:

  实验楼课程 :https://www.shiyanlou.com/courses/599

        https://www.shiyanlou.com/courses/reports/1292313

2,增强版实现效果

  支持城市切换

  支持公交到达圈时间选择(高德地图只支持60min以内?)

  支持房源选择

  效果图如下:

加载房源:

加载完成后:

3,实现细节

  架构:mysql储存房源数据,高德API + UIkit作为前端,django作为后端,数据交换

  3.1,主要步骤

  A. 爬取房源数据

    分别爬取58同城品牌公寓,安居客,链家房源数据,并存入mysql数据库,代码如下:

  爬取58同城品牌公寓:(下面代码为爬取北京数据,实现过程中爬取了南京和北京两城市数据,详细讲解参见https://www.cnblogs.com/silence-cho/p/10202552.html)

#coding:utf-8


import requests
from lxml import html
import csv
import re
from fontTools.ttLib import TTFont
import base64
import MySQLdb
import time
from download import get_user_agent

def download(url,headers=None,cookies=None,proxies=None,num_retries=3):  #支持user-agent和proxy
    #proxies = {"http": "http://10.10.1.10:3128", "https": "http://10.10.1.10:1080",}
    response=requests.get(url,headers=headers,cookies=cookies,proxies=proxies)
    if response.status_code and 500<=response.status_code<600:  # 出现服务器端错误时重试三次
        if num_retries > 0:
            response = download(url,headers,cookies,proxies,num_retries-1)
    return response

def convertNumber(html_page):

    base_fonts = ['uni9FA4', 'uni9F92', 'uni9A4B', 'uni9EA3', 'uni993C', 'uni958F', 'uni9FA5', 'uni9476', 'uni9F64',
                  'uni9E3A']
    base_fonts2 = ['&#x' + x[3:].lower() + ';' for x in base_fonts]  # 构造成 &#x9e3a; 的形式
    pattern = '(' + '|'.join(base_fonts2) + ')'

    font_base64 = re.findall("base64,(AA.*AAAA)", response.text)[0]  # 找到base64编码的字体格式文件
    font = base64.b64decode(font_base64)
    with open('58font2.ttf', 'wb') as tf:
        tf.write(font)
    onlinefont = TTFont('58font2.ttf')
    convert_dict = onlinefont['cmap'].tables[0].ttFont.tables['cmap'].tables[0].cmap  # convert_dict数据如下:{40611: 'glyph00004', 40804: 'glyph00009', 40869: 'glyph00010', 39499: 'glyph00003'
    new_page = re.sub(pattern, lambda x: getNumber(x.group(),convert_dict), html_page)
    return new_page

def getNumber(g,convert_dict):
    key = int(g[3:7], 16)  # '&#x9ea3',截取后四位十六进制数字,转换为十进制数,即为上面字典convert_dict中的键
    number = int(convert_dict[key][-2:]) - 1  # glyph00009代表数字8, glyph00008代表数字7,依次类推
    return str(number)

def getLocation(title):
    desc = title.split()
    if u'' in desc[0]or u'社区' in desc[0]:
        location = desc[0].strip(u'【整租】【合租】')+desc[2]
    else:
        location=desc[1]
    return location

def getAveragePrice(price):
    price_range = price.split('-')
    if len(price_range)==2:
        average_price = (int(price_range[0])+int(price_range[1]))/2
    else:
        average_price=price
    return average_price

if __name__ == '__main__':

    conn = MySQLdb.connect(host='localhost',user='root',passwd='',db='renthouse',charset='utf8',port=3306) #不要写成utf-8
    cursor = conn.cursor()
    cursor.execute("""CREATE TABLE IF NOT EXISTS 58house(
                        id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
                        city VARCHAR(32) NOT NULL,
                        title VARCHAR(128) NOT NULL,
                        location VARCHAR(128) NOT NULL,
                        room VARCHAR(128) NOT NULL ,
                        price VARCHAR(64) NOT NULL ,
                        average_price VARCHAR(64) NOT NULL ,
                        url VARCHAR(768) NOT NULL);""")
    conn.commit()
    #seed_url = "https://nj.58.com/pinpaigongyu/pn/{page}/"
    seed_url = "https://bj.58.com/pinpaigongyu/pn/{page}/"
    page = 0
    flag=True
    while flag:
        try:
            user_agent = get_user_agent()
            headers={"User-Agent":user_agent}
            page = page+1
            current_url=seed_url.format(page=page)
            print current_url
            response = download(url=current_url,headers=headers)
            new_page = convertNumber(response.text)
            tree = html.fromstring(new_page)
            li_tags = tree.xpath('//ul[@class="list"]/li')
            #print li_tags
            if (not li_tags) or page>600:
                print page
                flag=False
            for li_tag in li_tags:
                title = li_tag.xpath('.//div[@class="des strongbox"]/h2/text()')[0].strip()
                room = li_tag.xpath('.//p[@class="room"]/text()')[0].replace('\r\n', '').replace(r' ', '')
                price = li_tag.xpath('.//div[@class="money"]//b/text()')[0].strip().replace('\r\n', '').replace(r' ', '')
                url = li_tag.xpath('./a[@href]')[0].attrib['href'].strip()
                location = getLocation(title)
                average_price = getAveragePrice(price)
                cursor.execute("""INSERT INTO 58house(city,title,location,room,price,average_price,url) 
                        VALUES('%s','%s','%s','%s','%s','%s','%s');"""%(u'北京',title,location,room,price,average_price,url))
                conn.commit()
        except Exception as e:
            #raise
            print "download page %s error: %s"%(page,e)
        time.sleep(5) # 停顿时间小于5s时会要求图形验证码
    conn.close()
View Code

  爬取链家南京数据 

#coding:utf-8


import requests
from lxml import html
import time
from download import get_user_agent,get_proxy_ip
import MySQLdb

def download(url,headers=None,cookies=None,proxies=None,num_retries=3):  #支持user-agent和proxy
    response=requests.get(url,headers=headers,cookies=cookies,proxies=proxies)
    if response.status_code and 500<=response.status_code<600:  # 出现服务器端错误时重试三次
        if num_retries > 0:
            response = download(url,headers,cookies,proxies,num_retries-1)
    return response

def getLocation(title):
    desc = title.split()

    if u'合租' in desc[0] or u'整租' in desc[0]:
        try:
            location = desc[2]
        except IndexError as e:
            print e
            location = desc[0]
    else:
        location=desc[0]
    return location

if __name__ == '__main__':

    conn = MySQLdb.connect(host='localhost',user='root',passwd='',db='renthouse',charset='utf8',port=3306) #不要写成utf-8
    cursor = conn.cursor()
    cursor.execute("""CREATE TABLE IF NOT EXISTS lianjiahouse(
                        id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
                        city VARCHAR(32) NOT NULL,
                        title VARCHAR(128) NOT NULL,
                        location VARCHAR(128) NOT NULL,
                        room VARCHAR(128) NOT NULL ,
                        price VARCHAR(64) NOT NULL ,
                        url VARCHAR(128) NOT NULL);""")
    conn.commit()
    seed_url = "https://nj.lianjia.com/zufang/pg{page}/"
    page = 0
    while page<100:
        try:
            user_agent = get_user_agent()
            headers={"User-Agent":user_agent}
            proxies = get_proxy_ip()
            page = page+1
            current_url=seed_url.format(page=page)
            print current_url
            response = download(url=current_url,headers=headers,proxies=proxies)
            tree = html.fromstring(response.text)
            item_tags = tree.xpath('//div[@class="content__list"]/div')
            for item in item_tags:
                title = item.xpath('./div/p[1]/a/text()')[0].strip()
                room = item.xpath('./div/p[2]')[0].text_content().strip().replace('\n', '').replace(r' ', '')
                price = item.xpath('./div/span/em/text()')[0].strip()
                url = "https://nj.lianjia.com" + item.xpath('./div/p[1]/a')[0].attrib['href'].strip()
                location = getLocation(title)
                # print title, price, room, url, location

                cursor.execute("""INSERT INTO lianjiahouse(city,title,location,room,price,url)
                        VALUES('%s','%s','%s','%s','%s','%s');"""%(u'南京',title,location,room,price,url))
                conn.commit()
        except Exception as e:
            print "download page %s error: %s"%(page,e)
            # raise
        time.sleep(2) # 停顿2s
    conn.close()
View Code

  爬取安居客南京数据(关于ip代理和动态User-Agent参见:https://www.cnblogs.com/silence-cho/articles/10171416.html)

#coding:utf-8


import requests
from lxml import html
import MySQLdb
import time
from download import get_user_agent,get_proxy_ip

def download(url,headers=None,cookies=None,proxies=None,num_retries=3):  #支持user-agent和proxy
    #proxies = {"http": "http://10.10.1.10:3128", "https": "http://10.10.1.10:1080",}
    response=requests.get(url,headers=headers,cookies=cookies,proxies=proxies)
    if response.status_code and 500<=response.status_code<600:  # 出现服务器端错误时重试三次
        if num_retries > 0:
            response = download(url,headers,cookies,proxies,num_retries-1)
    return response

if __name__ == '__main__':

    conn = MySQLdb.connect(host='localhost',user='root',passwd='',db='renthouse',charset='utf8',port=3306) #不要写成utf-8
    cursor = conn.cursor()
    cursor.execute("""CREATE TABLE IF NOT EXISTS anjukehouse(
                        id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
                        city VARCHAR(32) NOT NULL,
                        title VARCHAR(128) NOT NULL,
                        location VARCHAR(128) NOT NULL,
                        room VARCHAR(128) NOT NULL ,
                        price VARCHAR(64) NOT NULL ,
                        url VARCHAR(128) NOT NULL);""")
    conn.commit()
    #seed_url = "https://nj.zu.anjuke.com/fangyuan/p{page}/"
    page = 0
    while page<50:
        try:
            user_agent = get_user_agent()
            headers = {"User-Agent": user_agent, "Referer": 'https://nanjing.anjuke.com/'}
            proxies = get_proxy_ip()
            page = page + 1
            current_url = seed_url.format(page=page)
            print current_url
            response = download(url=current_url, headers=headers, proxies=proxies)
            tree = html.fromstring(response.text)
            item_tags = tree.xpath('//div[@class="zu-itemmod  "]')  # 注意itemmod后面两个空格
            for item in item_tags:
                title = item.xpath('./div[1]/h3/a/text()')[0]
                price = item.xpath('./div[2]/p/strong/text()')[0]
                room = item.xpath('./div[1]/p')[0].text_content().strip().replace(u'\ue147', '|')
                url = item.xpath('./div[1]/h3/a')[0].attrib['href']
                location = item.xpath('./div[1]/address/a/text()')[0]
                # print title, price, room, url, location
                cursor.execute("""INSERT INTO anjukehouse(city,title,location,room,price,url)
                        VALUES('%s','%s','%s','%s','%s','%s');"""%(u'南京',title,location,room,price,url))
                conn.commit()
        except Exception as e:
            print "download page %s error: %s"%(page,e)
        time.sleep(2) # 停顿2s
    conn.close()
View Code

  B.前端页面架构代码(高德API + UIkit)

  整体页面map.html代码如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/>
    <link rel="stylesheet" href="https://cache.amap.com/lbs/static/jquery.range.css"/>
    <link rel="stylesheet" href="/static/UIkit/css/uikit.min.css">
    <link rel="stylesheet" href="/static/custom/housemap.css">
    <script src="http://webapi.amap.com/maps?v=1.3&key=22d3816e107f199992666d6412fa0691&plugin=AMap.ArrivalRange,AMap.Scale,AMap.Geocoder,AMap.Transfer,AMap.Autocomplete"></script>
    <script src="https://cache.amap.com/lbs/static/jquery-1.9.1.js"></script>
    <script src="https://cache.amap.com/lbs/static/jquery.range.js"></script>
    <script src="//webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
    <script src="/static/UIkit/js/uikit.min.js"></script>
    <title>Title</title>
</head>
<body>
<!--地图容器-->
<div id="container"></div>

<!--选择工作地点-->
<div class="control position-top" style='width:25rem;'>
    <h4 style='color:grey'>公交到达圈查询</h4>
    <div class="input-item">
        <div class="input-item-prepend">
            <label class="input-item-text">选择城市</label>
        </div>
        <select iname="c" id="city">
            <option selected value="南京市">南京</option>
            <option value="北京">北京</option>
            <option value="上海市">上海</option>
        </select>
    </div>
    <div class="input-item">
            <div class="input-item-prepend"><span class="input-item-text" style="width:8rem;" >选择工作地点:</span></div>
            <input id='work-location' type="text"  >
    </div>
    <div class="input-item" style='margin-bottom:2rem;'>
        <label>时长(分钟)</label>
        <input type="hidden" id="t" class="single-slider" value="45"/>
    </div>
    <div class="input-item">
        <div class="input-item-prepend">
            <label class="input-item-text">出行方式</label>
        </div>
        <select iname="v" id="v">
            <option selected value="SUBWAY,BUS">地铁+公交</option>
            <option value="SUBWAY">地铁</option>
            <option value="BUS">公交</option>
        </select>
        <input id="search" type="button" class="btn" value="查询"/>
        <input id="clear" type="button" class="btn" value="清除"/>
    </div>
</div>
<!--选择房源信息-->
<div class="control position-down" style='width:25rem;'>
    <h4 style='color:grey'>房屋分布查询</h4>
    <div class="input-item">
        <div class="input-item-prepend">
            <label class="input-item-text">房屋来源</label>
        </div>
        <select iname="v" id="houseSource">
            <option selected value="pinPaiHouse">58品牌公寓</option>
            <option value="AnJuKe">安居客</option>
            <option value="LianJia">链家</option>
        </select>
    </div>
    <div class="input-item">
        <div class="input-item-prepend">
            <label class="input-item-text" >房租价格</label>
        </div>
        <select iname="v" id="price">
            <option selected value="0">0-1000</option>
            <option value="1">1000-1500</option>
            <option value="2">1500-2000</option>
            <option value="3">2000-3000</option>
            <option value="4">3000-4000</option>
            <option value="5">4000-5000</option>
            <option value="6">5000-6000</option>
            <option value="7">6000-8000</option>
            <option value="8">大于8000</option>
        </select>
    </div>
    <div class="input-item">
        <input id="search-house" type="button" class="btn" data-uk-modal="{target:'#my-id',bgclose:false}" value="查询"/>
        <input id="clear-house" type="button" class="btn" value="清除"/>
    </div>
</div>

<!--公交路线规划图-->
<div id="transfer_panel"></div>

<!--模态对话框-->
<div id="my-id" class="uk-modal">
    <div class="uk-modal-dialog uk-margin-auto-vertical">
        <a class="uk-modal-close uk-close"></a>
        <div class="uk-modal-header">
            <h2 class="uk-modal-title">加载房源信息</h2>
        </div>
        <div class="uk-modal-body">
            <p id="load">如果没加载,请刷新</p>
            <i class="uk-icon-spinner uk-icon-spin uk-icon-large"></i>
            <p>如果加载不成功请刷新</p>
        </div>
    </div>
</div>

<script>
    var map = new AMap.Map("container", {
        resizeEnable: true,
        zoomEnable: true,
        zoom: 11
    });

    var scale = new AMap.Scale();
    map.addControl(scale);
    var arrivalRange = new AMap.ArrivalRange();
    var x, y, t, vehicle = "SUBWAY,BUS";
    var workAddress, workMarker;
    var polygonArray = [];
    var geocoder;
    var cityName;
    map.getCity(function (info) {
        cityName = info.city;
    });

    //切换城市地图,根据cityname、adcode、citycode设置地图位置
    $('#city').on('change',function () {
          cityName = $('#city').val(); //可以是cityname、adcode、citycode
          if (!cityName) {
            cityName = "南京市";
          }
          delWorkLocation();
          delHouseInfo();
          map.setCity(cityName)
    });


    //id为work-location的input标签,输入时自动补全
    var auto = new AMap.Autocomplete({
        input: "work-location"
    });
    //添加监听事件,选择一条提示时执行workLocationSelected
    AMap.event.addListener(auto, "select", workLocationSelected);

    //标记出选择的工作地点
    function workLocationSelected(e) {
        workAddress = e.poi.name;   //选择的信息的地理位置名字
        //workLocation =e.poi.location
        //x = workLocation.getLng();
        //y = workLocation.getLat();
        //console.log(x,y);
        loadWorkLocation();
    }

    //点击地图获取坐标
    function getLnglat(e) {
        var lnglat = e.lnglat;
        regeoCode(lnglat);
    }
    map.on( 'click', getLnglat);

    function regeoCode(lnglat) {
        delWorkLocation();
        if(!geocoder){
            geocoder = new AMap.Geocoder({
                city: cityName, //城市设为南京,默认:“全国”
                radius: 1000 //范围,默认:500
            });
        }
        x = lnglat.getLng();
        y = lnglat.getLat();
        geocoder.getAddress(lnglat, function(status, result) {
            if (status === 'complete'&&result.regeocode) {
                var address = result.regeocode.formattedAddress.slice(6); //去掉字符窜开头的江苏省南京市
                document.getElementById('work-location').value = address;
                loadWorkMarker(x,y,address);
                loadWorkRange();
                map.setZoomAndCenter(12, [x, y]);
            }else{alert(JSON.stringify(result))}
        });
    }

    function loadWorkLocation() {
        delWorkLocation();
        if(!geocoder){
            geocoder = new AMap.Geocoder({
                city: cityName, //城市设为南京,默认:“全国”
                radius: 1000 //范围,默认:500
            });
        }
        geocoder.getLocation(workAddress, function (status, result) {
            if (status === "complete" && result.info === 'OK') {
                var geocode = result.geocodes[0];    //根据workAddress位置名字,查找其坐标信息
                x = geocode.location.getLng();
                y = geocode.location.getLat();
                loadWorkMarker(x, y, workAddress);
                loadWorkRange();
                map.setZoomAndCenter(12, [x, y]);
            }
        });
    }

    function delWorkLocation() {
        if (polygonArray) map.remove(polygonArray);
        if (workMarker) map.remove(workMarker);
        polygonArray = [];
    }

    //ar content = '<div class="marker-route marker-marker-bus-from">工作地点</div>';
    //标记出选择的工作地点
    function loadWorkMarker(x, y, locationName) {
        if(!workMarker){
            workMarker = new AMap.Marker({
                map:map,
                title: locationName,
                icon: 'http://webapi.amap.com/theme/v1.3/markers/n/mark_r.png',
                position: [x, y]
            });
    }else{
            map.remove(workMarker);
            workMarker = new AMap.Marker({
                map:map,
                title: locationName,
                icon:'http://webapi.amap.com/theme/v1.3/markers/n/mark_r.png',
                position: [x, y]
            });}
    }

    //时间进度条取值,jquery插件
    $(function(){
        $('.single-slider').jRange({
            onstatechange: loadWorkRange,
            from: 1,
            to: 60,
            step: 1,
            scale: [15,30,45,60],
            format: '%s',
            width: 400,
            showLabels: true,
            showScale: true
        });
    });
    $('#search').on('click', loadWorkRange);
    $('#v').on('change', loadWorkRange);
    $('#clear').on('click', function(){map.remove(polygonArray)});

    //标记出通过vehicle交通,t时间内能到达的范围
    function loadWorkRange() {
        if (polygonArray) map.remove(polygonArray);
        if(x==null|y==null){
                        alert("请先选择工作地点");
                    }
        t = $("#t").val();
        vehicle = $("#v").val();
        //console.log(t,vehicle);
        arrivalRange.search([x, y], t, function (status, result) {
            //console.log(result.bounds);
            if (result.bounds) {
                for (var i = 0; i < result.bounds.length; i++) {
                    var polygon = new AMap.Polygon({
                        map: map,
                        fillColor: "#3f67a5",
                        fillOpacity: "0.4",
                        strokeColor: "#3f67a5",
                        strokeOpacity: "0.8",
                        strokeWeight: 1
                    });
                    polygon.setPath(result.bounds[i]);
                    polygonArray.push(polygon);
                }

            }
        }, {
            policy: vehicle
        });
    }



    // 下面代码关于载入房源信息

    var rentMarkerArray = [];
    var amapTransfer;
    //信息窗口
    var infoWindow = new AMap.InfoWindow({
        offset: new AMap.Pixel(0, -37)
    });

    function delHouseInfo(){
        if(rentMarkerArray) map.remove(rentMarkerArray);
        rentMarkerArray=[];
        infoWindow.close();
        if(amapTransfer) amapTransfer.clear();
    }

    //点击发送ajax请求,查询房源信息
    $('#search-house').click(function () {
        delHouseInfo();
        var source = $('#houseSource').val();
        var price  =$('#price').val();
        var current_city = $('#city').val();
        var rent_house = new Set();
        var house_count=0;
        $.ajax({
            url:'/houseinfo/',
            type:'POST',
            data:{source:source,
                price:price,
                current_city:current_city,
                csrfmiddlewaretoken:'{{ csrf_token }}'
            },
            dataType:'json',
            success:function (jsonData) {
                //console.log(jsonData);
                $.each(jsonData,function (i,item) {
                    house_count = house_count+1;
                    rent_house.add([jsonData[i][2],jsonData[i][3],jsonData[i][4],jsonData[i][5],jsonData[i][7]])//title,location,room,price,url
                });
                if(house_count==0){
                    alert('未找到相关房源信息,请重新搜索!');
                }
                $('#load').text('正在加载中,总房源数:'+house_count);

                rent_house.forEach(function(element,index) {
                    addMarkerByAddress(element,house_count);
                    house_count = house_count-1;
                });
            }
        });
    });

    //根据房源的位置信息,转换为地图坐标信息
    function addMarkerByAddress(element,house_count) {
        if(rentMarkerArray) map.remove(rentMarkerArray);

        geocoder = new AMap.Geocoder({
            city: cityName, //城市设为南京,默认:“全国”
            radius: 1000 //范围,默认:500
        });

        //console.log(element[1]);
        geocoder.getLocation(element[1], function (status, result) {
            if(house_count==1){
                        var modal = UIkit.modal('#my-id');
                        if ( modal.isActive() )modal.hide();
                        $('#load').text('如果没加载,请刷新');
                    }
            if (status === "complete" && result.info === 'OK') {
                var geocode = result.geocodes[0];    //根据位置名字,查找其坐标信息
                var x1 = geocode.location.getLng();
                var y1 = geocode.location.getLat();
                //console.log(element[0]);
                loadHouseMarker(x1, y1, element);
            }

        });

    }
    // 在地图上标记房源位置,并绑定点击事件(显示房源信息,加载路线规划信息)
    function loadHouseMarker(x1,y1,element){
        var houseTitle=element[0];
        var houseMarker;
        AMapUI.loadUI(['overlay/SimpleMarker'], function(SimpleMarker) {
            houseMarker=new SimpleMarker({
                            iconLabel: 'H',
                            //自定义图标地址
                            iconStyle: {src: '//webapi.amap.com/theme/v1.3/markers/b/mark_b.png',
                                            style: {
                                                width: '20px',
                                                height: '60px'
                                            }},
                            //设置基点偏移
                            offset: new AMap.Pixel(-19, -60),
                            map: map,
                            showPositionPoint: true,
                            title: houseTitle,
                            position: [x1, y1],
                        });
        houseMarker.content="<div>房源:<a target = '_blank' href='" + element[4] + "'>" + element[0] +
                "</a><div><div>价格:"+element[3]+"</div><div>房间信息:"+element[2]+"</div><div>地址:"+element[1]+"</div>"
        rentMarkerArray.push(houseMarker);
        houseMarker.on('click',function (e) {
            infoWindow.setContent(e.target.content);
            infoWindow.open(map,e.target.getPosition());
            if(amapTransfer) amapTransfer.clear();
            amapTransfer = new AMap.Transfer({
                        map: map,
                        policy: AMap.TransferPolicy.LEAST_TIME,
                        city: cityName,
                        panel: 'transfer_panel'
                    });
            if(x==null|y==null){
                        alert("请先选择工作地点");
                    }
            amapTransfer.search(new AMap.LngLat(x,y), new AMap.LngLat(x1, y1));
        });
        });
    }
    $('#clear-house').on('click', delHouseInfo);


</script>
</body>
</html>
View Code

  上面页面中的js代码可以拆分为两块,一是选择工作地点和公交到达圈,二是加载房源信息

        选择工作地点:根据用户输入信息(提示框)或在地图上选择地点来标记工作地点,然后用多边形标记出一定时间内公交到达圈,相应代码如下。

var map = new AMap.Map("container", {
        resizeEnable: true,
        zoomEnable: true,
        zoom: 11
    });

    var scale = new AMap.Scale();
    map.addControl(scale);
    var arrivalRange = new AMap.ArrivalRange();
    var x, y, t, vehicle = "SUBWAY,BUS";
    var workAddress, workMarker;
    var polygonArray = [];
    var geocoder;
    var cityName;
    map.getCity(function (info) {
        cityName = info.city;
    });

    //切换城市地图,根据cityname、adcode、citycode设置地图位置
    $('#city').on('change',function () {
          cityName = $('#city').val(); //可以是cityname、adcode、citycode
          if (!cityName) {
            cityName = "南京市";
          }
          delWorkLocation();
          delHouseInfo();
          map.setCity(cityName)
    });


    //id为work-location的input标签,输入时自动补全
    var auto = new AMap.Autocomplete({
        input: "work-location"
    });
    //添加监听事件,选择一条提示时执行workLocationSelected
    AMap.event.addListener(auto, "select", workLocationSelected);

    //标记出选择的工作地点
    function workLocationSelected(e) {
        workAddress = e.poi.name;   //选择的信息的地理位置名字
        //workLocation =e.poi.location
        //x = workLocation.getLng();
        //y = workLocation.getLat();
        //console.log(x,y);
        loadWorkLocation();
    }

    //点击地图获取坐标
    function getLnglat(e) {
        var lnglat = e.lnglat;
        regeoCode(lnglat);
    }
    map.on( 'click', getLnglat);

    function regeoCode(lnglat) {
        delWorkLocation();
        if(!geocoder){
            geocoder = new AMap.Geocoder({
                city: cityName, //城市设为南京,默认:“全国”
                radius: 1000 //范围,默认:500
            });
        }
        x = lnglat.getLng();
        y = lnglat.getLat();
        geocoder.getAddress(lnglat, function(status, result) {
            if (status === 'complete'&&result.regeocode) {
                var address = result.regeocode.formattedAddress.slice(6); //去掉字符窜开头的江苏省南京市
                document.getElementById('work-location').value = address;
                loadWorkMarker(x,y,address);
                loadWorkRange();
                map.setZoomAndCenter(12, [x, y]);
            }else{alert(JSON.stringify(result))}
        });
    }

    function loadWorkLocation() {
        delWorkLocation();
        if(!geocoder){
            geocoder = new AMap.Geocoder({
                city: cityName, //城市设为南京,默认:“全国”
                radius: 1000 //范围,默认:500
            });
        }
        geocoder.getLocation(workAddress, function (status, result) {
            if (status === "complete" && result.info === 'OK') {
                var geocode = result.geocodes[0];    //根据workAddress位置名字,查找其坐标信息
                x = geocode.location.getLng();
                y = geocode.location.getLat();
                loadWorkMarker(x, y, workAddress);
                loadWorkRange();
                map.setZoomAndCenter(12, [x, y]);
            }
        });
    }

    function delWorkLocation() {
        if (polygonArray) map.remove(polygonArray);
        if (workMarker) map.remove(workMarker);
        polygonArray = [];
    }

    //ar content = '<div class="marker-route marker-marker-bus-from">工作地点</div>';
    //标记出选择的工作地点
    function loadWorkMarker(x, y, locationName) {
        if(!workMarker){
            workMarker = new AMap.Marker({
                map:map,
                title: locationName,
                icon: 'http://webapi.amap.com/theme/v1.3/markers/n/mark_r.png',
                position: [x, y]
            });
    }else{
            map.remove(workMarker);
            workMarker = new AMap.Marker({
                map:map,
                title: locationName,
                icon:'http://webapi.amap.com/theme/v1.3/markers/n/mark_r.png',
                position: [x, y]
            });}
    }

    //时间进度条取值,jquery插件
    $(function(){
        $('.single-slider').jRange({
            onstatechange: loadWorkRange,
            from: 1,
            to: 60,
            step: 1,
            scale: [15,30,45,60],
            format: '%s',
            width: 400,
            showLabels: true,
            showScale: true
        });
    });
    $('#search').on('click', loadWorkRange);
    $('#v').on('change', loadWorkRange);
    $('#clear').on('click', function(){map.remove(polygonArray)});

    //标记出通过vehicle交通,t时间内能到达的范围
    function loadWorkRange() {
        if (polygonArray) map.remove(polygonArray);
        if(x==null|y==null){
                        alert("请先选择工作地点");
                    }
        t = $("#t").val();
        vehicle = $("#v").val();
        //console.log(t,vehicle);
        arrivalRange.search([x, y], t, function (status, result) {
            //console.log(result.bounds);
            if (result.bounds) {
                for (var i = 0; i < result.bounds.length; i++) {
                    var polygon = new AMap.Polygon({
                        map: map,
                        fillColor: "#3f67a5",
                        fillOpacity: "0.4",
                        strokeColor: "#3f67a5",
                        strokeOpacity: "0.8",
                        strokeWeight: 1
                    });
                    polygon.setPath(result.bounds[i]);
                    polygonArray.push(polygon);
                }

            }
        }, {
            policy: vehicle
        });
    }
View Code

    加载房源信息:将用户选择项通过ajax提交给后台,并解析后台返回的json数据,将房源点标记在地图上,且点击房源点时弹出房源信息和公交路线规划。代码如下:

// 下面代码关于载入房源信息

    var rentMarkerArray = [];
    var amapTransfer;
    //信息窗口
    var infoWindow = new AMap.InfoWindow({
        offset: new AMap.Pixel(0, -37)
    });

    function delHouseInfo(){
        if(rentMarkerArray) map.remove(rentMarkerArray);
        rentMarkerArray=[];
        infoWindow.close();
        if(amapTransfer) amapTransfer.clear();
    }

    //点击发送ajax请求,查询房源信息
    $('#search-house').click(function () {
        delHouseInfo();
        var source = $('#houseSource').val();
        var price  =$('#price').val();
        var current_city = $('#city').val();
        var rent_house = new Set();
        var house_count=0;
        $.ajax({
            url:'/houseinfo/',
            type:'POST',
            data:{source:source,
                price:price,
                current_city:current_city,
                csrfmiddlewaretoken:'{{ csrf_token }}'
            },
            dataType:'json',
            success:function (jsonData) {
                //console.log(jsonData);
                $.each(jsonData,function (i,item) {
                    house_count = house_count+1;
                    rent_house.add([jsonData[i][2],jsonData[i][3],jsonData[i][4],jsonData[i][5],jsonData[i][7]])//title,location,room,price,url
                });
                if(house_count==0){
                    alert('未找到相关房源信息,请重新搜索!');
                }
                $('#load').text('正在加载中,总房源数:'+house_count);

                rent_house.forEach(function(element,index) {
                    addMarkerByAddress(element,house_count);
                    house_count = house_count-1;
                });
            }
        });
    });

    //根据房源的位置信息,转换为地图坐标信息
    function addMarkerByAddress(element,house_count) {
        if(rentMarkerArray) map.remove(rentMarkerArray);

        geocoder = new AMap.Geocoder({
            city: cityName, //城市设为南京,默认:“全国”
            radius: 1000 //范围,默认:500
        });

        //console.log(element[1]);
        geocoder.getLocation(element[1], function (status, result) {
            if(house_count==1){
                        var modal = UIkit.modal('#my-id');
                        if ( modal.isActive() )modal.hide();
                        $('#load').text('如果没加载,请刷新');
                    }
            if (status === "complete" && result.info === 'OK') {
                var geocode = result.geocodes[0];    //根据位置名字,查找其坐标信息
                var x1 = geocode.location.getLng();
                var y1 = geocode.location.getLat();
                //console.log(element[0]);
                loadHouseMarker(x1, y1, element);
            }

        });

    }
    // 在地图上标记房源位置,并绑定点击事件(显示房源信息,加载路线规划信息)
    function loadHouseMarker(x1,y1,element){
        var houseTitle=element[0];
        var houseMarker;
        AMapUI.loadUI(['overlay/SimpleMarker'], function(SimpleMarker) {
            houseMarker=new SimpleMarker({
                            iconLabel: 'H',
                            //自定义图标地址
                            iconStyle: {src: '//webapi.amap.com/theme/v1.3/markers/b/mark_b.png',
                                            style: {
                                                width: '20px',
                                                height: '60px'
                                            }},
                            //设置基点偏移
                            offset: new AMap.Pixel(-19, -60),
                            map: map,
                            showPositionPoint: true,
                            title: houseTitle,
                            position: [x1, y1],
                        });
        houseMarker.content="<div>房源:<a target = '_blank' href='" + element[4] + "'>" + element[0] +
                "</a><div><div>价格:"+element[3]+"</div><div>房间信息:"+element[2]+"</div><div>地址:"+element[1]+"</div>"
        rentMarkerArray.push(houseMarker);
        houseMarker.on('click',function (e) {
            infoWindow.setContent(e.target.content);
            infoWindow.open(map,e.target.getPosition());
            if(amapTransfer) amapTransfer.clear();
            amapTransfer = new AMap.Transfer({
                        map: map,
                        policy: AMap.TransferPolicy.LEAST_TIME,
                        city: cityName,
                        panel: 'transfer_panel'
                    });
            if(x==null|y==null){
                        alert("请先选择工作地点");
                    }
            amapTransfer.search(new AMap.LngLat(x,y), new AMap.LngLat(x1, y1));
        });
        });
    }
    $('#clear-house').on('click', delHouseInfo);
View Code

   C.后端django视图函数

视图函数

def getMap(request):

    return render(request,'map.html')

def getHouseInfo(request):

    if request.method=='POST':
        source = request.POST.get('source')
        house_table = source_dict[source]
        city = request.POST.get('current_city')[0:2].encode('utf-8')
        print city,type(city),type(house_table)
        i = int(request.POST.get('price'))
        price_range = price_list[i].split('-')
        query=''
        if len(price_range)==2:
            min_price = price_range[0]
            max_price = price_range[1]
            query = 'SELECT * FROM %s WHERE city="%s" AND CONVERT(average_price, UNSIGNED INTEGER)>%s AND CONVERT(average_price, UNSIGNED INTEGER)<%s;'%(house_table,city,min_price,max_price)
        else:
            query= 'SELECT * FROM %s WHERE city="%s" AND CONVERT(average_price, UNSIGNED INTEGER)>%s;'%(house_table,city,price_range[0])

        conn = MySQLdb.connect(host="localhost", user="root", passwd="", db='renthouse', charset='utf8', port=3306)
        cursor = conn.cursor()
        print query
        cursor.execute(query)
        data = cursor.fetchall()
        print data
        conn.close()
        return HttpResponse(json.dumps(data))
View Code

url映射

from django.conf.urls import url
from django.contrib import admin
from houseMap import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^housemap/',views.getMap),
    url(r'^houseinfo/',views.getHouseInfo),
]
View Code

 

posted @ 2024-09-21 14:39  silence_cho  阅读(36)  评论(0编辑  收藏  举报