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] # 构造成 鸺 的形式 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) # '麣',截取后四位十六进制数字,转换为十进制数,即为上面字典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()
爬取链家南京数据
#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()
爬取安居客南京数据(关于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()
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>
上面页面中的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 }); }
加载房源信息:将用户选择项通过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);
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))
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), ]