高德地图+58租房

开发工具准备:

  • 开发工具:PyCharm
  • 内置模块:csv
  • 第三方模块:requests、beautifulsoup4
  • 地图:高德地图JS

requests模块:用于实现HTTP请求,请求方式主要是GET和POST。
beautifulsoup模块:用于从HTML和XML文件中提取数据。
csv模块:csv(逗号分隔值)格式是电子表格和数据库最常用的导入和导出格式。csv模块实现了以csv格式读取和写入表格数据的功能。

项目组织结构:

在这里插入图片描述

  • crawl.py文件:实现爬取58同城的房源信息,运行之后生成renting.csv文件
  • web.py文件:用于模拟Web后台服务
  • index.html文件:用于实现高德地图网页

爬取房源数据并生成文件:

1.请求地址的获取

浏览器打开【58同城官网】→左上角定位城市选择【西安】(可以自己修改,我的项目是西安)→在【西安房产】里面选择【品牌公寓】,会重新打开网页→位置选择【雁塔→大雁塔】(也可以自己设置租金,我没有设置)。此时的网址是:

https://xa.58.com/dayanta/pinpaigongyu/?PGTID=0d100000-001e-3a4e-2556-28a1090be95a&ClickID=4

把问号后面的去掉之后,地址同样有效,修改后的请求地址如下:

https://xa.58.com/dayanta/pinpaigongyu/

如果设置了租金(比如租金是1000-1500元),那么请求地址就是:

https://xa.58.com/dayanta/pinpaigongyu/?minprice=1000_1500

2.分析房源数据

(1)打开浏览器,在地址栏中输入上面的请求地址(https://xa.58.com/dayanta/pinpaigongyu/),打开网页之后,快捷键<Ctrl+Shift+C>打开查看器。

(2)点击第一条房源信息(紫色区域),在查看器中显示该房源信息所对应的网页源码,在源码中能看到所有的房源信息都在< ul class=“list”>标签中,而每一条房源信息对应一个< li >标签。
在这里插入图片描述

(3)每一个< li >标签的内容如下,里面包含很多信息,而保存在CSV文件当中的信息主要是:房子的标题、房子位置、房子链接等。
在这里插入图片描述

分析可以得出:
①房子的标题主要在:< li >标签下的< div class=“img”>标签下的< img>标签的alt属性
在这里插入图片描述
获取房子标题的代码如下:(所有房源信息存在house里面)

# 1.获取房子标题
house_title=house.find('div',class_='img').img.get('alt')

②房子位置主要是:根据房子标题按照空格分割之后的第二个值(比如房子标题是:【合租】大雁塔 曲江春晓苑 5室次卧,按照空格分割之后就是:【合租】大雁塔、 曲江春晓苑、 5室次卧,那么房子位置就是:曲江春晓苑)

获取房子位置的代码如下:

# 对标题进行分隔
house_info_list=house_title.split()
# 2.获取房子位置
house_location=house_info_list[1]

③房子链接地址就是:< li >标签下的< a >标签的href属性
在这里插入图片描述
获取房子链接地址的代码如下:

# 3.获取房子连接地址
house_url=house.select("a")[0]["href"]

3.代码实现爬取房源信息并且生成renting.csv文件

get_html()方法主要获取符合标准的每条房子的全部信息,write_file()方法用于将房屋信息分类(房源标题、位置、房源链接)并写入文件。主要分为:爬取数据(requests模块)→解析数据(beautifulsoup模块)→写入文件(csv模块)

import csv                         # csv文件模块
from bs4 import BeautifulSoup      # 网页解析模块
import requests                    # 网络请求模块

#获取符合标准的每条房子的全部信息
def get_html():
    # 爬取数据的网址
    url='https://xa.58.com/dayanta/pinpaigongyu/'

    # 打开renting.csv文件,如果没有就创建一个,并设置写入模式
    csv_file=open('renting.csv','w',encoding='utf_8_sig',newline='')
    # 创建writer对象
    writer=csv.writer(csv_file,dialect='excel')

    response=requests.get(url)  # 1.抓取目标页面
    response.encoding='utf-8'   # 设置编码方式

    # 2.创建一个BeautifulSoup对象,获取页面正文
    html=BeautifulSoup(response.text,"html.parser")
    #print(html)
    # 获取当前页面的房子信息(list类的li标签)
    house_list=html.select(".list>li")
    #print(house_list)

    write_file(house_list,writer)  # 3.调用写入数据的方法
    csv_file.close()               # 关闭文件



#将房屋信息分类(房子标题、房子位置、房子链接),并写入文件中
def write_file(house_list,writer):
    # 遍历房子信息
    for house in house_list:
        if house!=None:
            # 1.获取房子标题
            house_title=house.find('div',class_='img').img.get('alt')

            # 对标题进行分隔
            house_info_list=house_title.split()
            # 2.获取房子位置
            house_location=house_info_list[1]

            # 3.获取房子连接地址
            house_url=house.select("a")[0]["href"]

            #写入一行数据
            writer.writerow([house_title,house_location,house_url])


if __name__=='__main__':
    get_html()

运行代码生成renting.csv文件,文件内容如下:

在这里插入图片描述

申请高德地图API开发者的Key:
(1)浏览器打开高德地图API官网https://lbs.amap.com/,然后单击右上角的【登录】按钮进行登录
(2)登录完成之后,在首页的右上角单击【控制台】,在左侧栏中选择【应用管理】→【我的应用】
(3)点击右上角的【创建新应用】,随便写个应用名称和应用类型,写好之后,点击【添加】按钮来添加key
(4)key名称自己写,服务平台选择【Web端(JS API)】,提交之后就会出现key
如下图:
在这里插入图片描述

高德地图index.html代码如下:

<!doctype html>
<html>

    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">

        <link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/>
        <link rel="stylesheet" href="https://cache.amap.com/lbs/static/jquery.range.css"/>
        <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css" />

        <title>高德地图+58租房</title>

        <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="http://cache.amap.com/lbs/static/es5.min.js"></script>
        <!-- 加载地图JSAPI脚本 -->
        <script src="https://webapi.amap.com/maps?v=1.4.15&key=2f15243fc3a6043affee98d60c8d4e0b&plugin=AMap.ArrivalRange,AMap.Scale,AMap.Geocoder,AMap.Transfer,AMap.Driving,AMap.Walking,AMap.Riding,AMap.Autocomplete"></script>

        <style>

            /*面板控制样式*/
            .control-panel{
                position:absolute;
                top: 30px;
                right: 20px;
            }

            /*面板内容样式*/
            .control-entry{
                width: 300px;
                background-color: rgba(119,136,153,0.8);
                font-family: fantasy,sans-serif;
                text-align: left;
                color: white;
                overflow: hidden;
                padding: 10px;
                margin-bottom: 10px;
            }

            /*文字与右侧距离*/
            .control-input{
                margin-left: 100px;
            }

            /*输入框宽度*/
            .control-input input[type="text"]{
                width: 150px;
            }

            /*文字样式*/
            .control-panel label{
                float: left;
                width: 100px;
            }

            /*路线规划信息窗体样式*/
            #transfer-panel{
                position: absolute;
                background-color: white;
                max-height: 80%;
                overflow-y: auto;
                top: 30px;
                left: 20px;
                width: 250px;
            }
        </style>
    </head>


    <body>
        <div id="container"></div>

        <div class="control-panel">
            <!--显示输入地址面板-->
            <div class="control-entry">
                <label>输入工作地点:</label>
                <div class="control-input">
                    <input id="work-location" type="text">
                </div>
            </div>
            <!--显示通勤方式面板-->
            <div class="control-entry">
                <label>选择通勤方式:</label>
                <div class="control-input">
                    <input type="radio" name="vehicle" value="SUBWAY,BUS" onclick="takeWay(this)" />公交
                    <input type="radio" name="vehicle" value="CAR" onclick="takeWay(this)"/>驾车
                    <input type="radio" name="vehicle" value="WALK" onclick="takeWay(this)"/>步行
                    <input type="radio" name="vehicle" value="RIDE" onclick="takeWay(this)"/>骑行
                </div>
            </div>
            <!--显示导入房源面板-->
            <div class="control-entry">
                <label>导入房源文件:</label>
                <div class="control-input">
                    <input type="file" name="file" onchange="importRentInfo(this)">
                </div>
            </div>
        </div>
        <div id="transfer-panel"></div>



        <script>
            //地图部分
            var map = new AMap.Map('container', {
                resizeEnable: true,               //是否监控地图容器尺寸变化,页面可调整大小
                zoomEnable:true,                  // 可缩放
                zoom:11,                          //初始化地图层级,缩放等级,数字越大离地球越近
                center: [116.397428, 39.90923]    //初始化地图中心点,这里使用的是北京的经纬度
            });
            //添加标尺
            var scale=new AMap.Scale();
            map.addControl(scale);

            //经度、纬度、时间、通勤方式(默认是地铁+公交)
            var x,y,t,vehicle="SUBWAY,BUS";
            //工作地点,工作标记
            var workAddress,workMarker;
            //房源标记数组
            var rentMarkerArray=[];
            //多边形数组,存储到达范围的计算结果
            var polygonArray=[];
            //路线规划
            var amapTransfer;  //公交
            var amapDriving;   //架车
            var amapWalking;   //步行
            var amapRiding;    //骑行

            //到达范围对象
            var arrivalRange= new AMap.ArrivalRange();
            //信息窗体对象
            var infoWindow=new AMap.InfoWindow({
                offset: new AMap.Pixel(0,-30)
            });
            //地址自动补全对象
            var auto=new AMap.Autocomplete({
                //根据id指定输入内容
                //上面input标签,id为work-location的文本框,也就是输入工作地点文本框
                input:"work-location"
            });


            //1.添加事件监听,在选择完地址以后调用workLocationSelected方法
            AMap.event.addListener(auto,"select",workLocationSelected);


            //2.选择工作地点后触发的方法
            function workLocationSelected(e) {
                //更新工作地点
                workAddress=e.poi.name;
            }

            //3.选择通勤方式
            function takeWay(radio) {
                vehicle=radio.value;
                if (amapDriving)
                    amapDriving.clear();  //清空驾车路线规划
                if (amapTransfer)
                    amapTransfer.clear();  //清空公交路线规划
                if (amapWalking)
                    amapWalking.clear();   //清空步行路线规划
                if (amapRiding)
                    amapRiding.clear();    //清空骑行路线规划
                //调用加载1小时到达区域的方法
                loadWorkLocation();
            }

            //5.清除已有的到达区域
            function delWorkLocation() {
                if (polygonArray)
                    map.remove(polygonArray);   //清空存储到达范围的计算结果
                if (workMarker)
                    map.remove(workMarker);    //清空工作标记
                polygonArray=[];
            }

            //6.加载工作地点标记
            function loadWorkMarker(x,y,locationName) {
                workMarker = new AMap.Marker({
                    map:map,
                    title:locationName,
                    icon:'http://webapi.amap.com/theme/v1.3/markers/n/mark_r.png',
                    position:[x,y]
                });
            }

            //7.加载到达范围
            function loadWorkRange(x,y,t,color,v) {
                arrivalRange.search([x,y],t,function (status,result) {
                    if(result.bounds){
                        for (var i=0;i< result.bounds.length;i++){
                            //多边形对象
                            var polygon=new AMap.Polygon({
                                map:map,
                                fillColor:color,    //填充色
                                fillOpacity:"0.4",  //透明度
                                strokeWeight:1      //线宽
                            });
                            //到达范围的多边形路径
                            polygon.setPath(result.bounds[i]);
                            //增加多边形
                            polygonArray.push(polygon);
                        }
                    }

                },{
                    policy:v
                });
            }

            //4.加载到达范围
            function loadWorkLocation() {
                //清除已有的到达区域
                delWorkLocation();
                //创建地址坐标对象
                var geocoder=new AMap.Geocoder({
                    city:"西安",
                    radius:1000
                });
                //获取位置
                geocoder.getLocation(workAddress,function (status,result) {
                    if (status==="complete" && result.info==='OK'){
                        var geocode=result.geocodes[0];   // 获取地址编码
                        x=geocode.location.getLng();      //经度
                        y=geocode.location.getLat();      //纬度
                        //加载工作地点标记
                        loadWorkMarker(x,y);
                        //如果是公交,才加载工作地点1小时内到达的范围
                        if(vehicle==="SUBWAY,BUS")
                            loadWorkRange(x,y,60,'#3f67a5',vehicle);
                        //地图移动到工作地点的位置
                        map.setZoomAndCenter(12,[x,y]);
                    }
                });
            }

            //8.导入房源信息触发的方法
            function importRentInfo(fileInfo) {
                //获取房源文件名称
                var file=fileInfo.files[0].name;
                //加载房源位置
                loadRentLocationByFile(file);
            }

            //10.清除现有房源标记
            function delRentLocation() {
                if (rentMarkerArray)
                    map.remove(rentMarkerArray);
                rentMarkerArray=[];
            }

            //9.加载房源位置
            function loadRentLocationByFile(fileName){
                //清除现有房源标记
                delRentLocation()
                //所有的地点都记录在集合中
                var rent_locations=new Set();
                //获取文件中的房源信息
                $.get(fileName,function (data) {
                    //分割信息
                    data=data.split("\n");
                    //遍历房源位置
                    data.forEach(function (item,index) {
                        rent_locations.add(item.split(",")[1]);
                    });
                    rent_locations.forEach(function (element,index) {
                        //加上房源标记
                        addMarkerByAddress(element);
                    });
                });
            }


            //11.添加房源位置标记
            function addMarkerByAddress(address) {
                //地理编码对象
                var geocoder=new AMap.Geocoder({
                    city:"西安",
                    radius:1000
                });
                //获取位置
                geocoder.getLocation(address,function (status,result) {
                    if (status==="complete" && result.info==='OK'){
                        var geocode=result.geocodes[0];   // 获取地址编码

                        //标记对象
                        rentMarker=new AMap.Marker({
                            map:map,                       //显示标记的地图
                            title:address,                 //鼠标移动至标记时所显示的文字
                            //标记图标地址
                            icon:'http://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
                            //位置
                            position:[geocode.location.getLng(),geocode.location.getLat()]
                        });

                        rentMarkerArray.push(rentMarker);

                        //相关房源网络地址
                        rentMarker.content="<div>房源:<a target='_blank' href='http://xa.58.com/pinpaigongyu/?key=" + address + "' >" + address + "</a><div>"

                        //标记事件处理
                        rentMarker.on('click',function (e){
                            //设置信息窗体显示的内容
                            infoWindow.setContent(e.target.content);
                            infoWindow.open(map,e.target.getPosition());

                            //公交路线规划
                            if(vehicle==="SUBWAY,BUS"){
                                //路线规划是否清除
                                if (amapTransfer)
                                    amapTransfer.clear();
                                //换乘对象
                                amapTransfer=new AMap.Transfer({
                                    map:map,
                                    policy:AMap.TransferPolicy.LEAST_TIME,
                                    city:"西安市",
                                    panel:'transfer-panel'
                                });
                                //根据起点、终点坐标查询换乘路线
                                amapTransfer.search(
                                    [
                                        {keyword:workAddress},
                                        {keyword:address}
                                    ],
                                    function (status,result) {}
                                )
                            }
                            //驾车路线规划
                            else if(vehicle==="CAR"){
                                //路线规划是否清除
                                if (amapDriving)
                                    amapDriving.clear();
                                //换乘对象
                                amapDriving=new AMap.Driving({
                                    map:map,
                                    panel:'transfer-panel'
                                });
                                //根据起点、终点坐标查询换乘路线
                                amapDriving.search(
                                    [
                                        {keyword:workAddress},
                                        {keyword:address}
                                    ],
                                    function (status,result) {}
                                )
                            }
                            //步行路线规划
                            else if(vehicle==="WALK"){
                                //路线规划是否清除
                                if (amapWalking)
                                    amapWalking.clear();
                                //换乘对象
                                amapWalking=new AMap.Walking({
                                    map:map,
                                    panel:'transfer-panel'
                                });
                                //根据起点、终点坐标查询换乘路线
                                amapWalking.search(
                                    [
                                        {keyword:workAddress},
                                        {keyword:address}
                                    ],
                                    function (status,result) {}
                                )
                            }
                            //骑行路线规划
                            else if(vehicle==="RIDE"){
                                //路线规划是否清除
                                if (amapRiding)
                                    amapRiding.clear();
                                //换乘对象
                                amapRiding=new AMap.Riding({
                                    map:map,
                                    panel:'transfer-panel'
                                });
                                //根据起点、终点坐标查询换乘路线
                                amapRiding.search(
                                    [
                                        {keyword:workAddress},
                                        {keyword:address}
                                    ],
                                    function (status,result) {}
                                )
                            }

                        });
                    }
                });

            }


        </script>
    </body>
</html>

代码很多啊,但是很好理解。其中大部分代码都是参考高德地图API官网的示例中心代码:

web.py文件实现模拟一个简单的web服务器,代码如下:

#导入服务器模块
from http.server import HTTPServer,CGIHTTPRequestHandler

# 指定端口
PORT=8000
# 创建服务器对象
httpd=HTTPServer(("",PORT),CGIHTTPRequestHandler)
print("serving at port",PORT)
# 反复处理连接请求
httpd.serve_forever()

运行web.py文件,在浏览器地址栏输入http://localhost:8000/

运行结果展示:

(1)初始显示效果如图:

在这里插入图片描述

(2)在编辑框输入工作地点,将显示自动补全的信息,如图所示:

在这里插入图片描述
(3)选择指定工作地点,再选择通勤方式,如果通勤方式是公交,就会显示1小时内可到达范围,如果通勤方式是其他(驾车、步行、骑行),就不显示1小时内可到达范围,因为1小时内可到达范围针对的是公交,如图所示:

①通勤方式选择的是公交,显示1小时内可到达范围

在这里插入图片描述
②通勤方式选择的是其他(比如驾车),不显示1小时内可到达范围

在这里插入图片描述
(4)单击选择文件按钮导入房源文件信息,在地图上显示房源位置标记(蓝色标记),如图所示:

在这里插入图片描述
(5)单击任意房源位置的标记,地图将显示起点至终点的路线规划图,并且在左侧显示具体信息。还可以根据不同的通勤方式显示路线规划图,如图所示:

①通勤方式为:驾车

在这里插入图片描述

②通勤方式为:步行

在这里插入图片描述
③通勤方式为:骑行

在这里插入图片描述
④通勤方式为:公交

在这里插入图片描述

(6)单击标记顶部的房源名称,将打开该房源相关信息的网页地址,如图所示:

在这里插入图片描述

在这里插入图片描述

转载请注明链接出处,谢谢!
自己完成的一个小项目,记录一下吧。
有什么问题或者需要源代码的,可以评论。我看到的就会回复!!!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值