蘑菇租房爬虫数据分析

一、先上python代码

#coding:utf-8

import requests
import random
import json
import datetime
import pandas as pd
import threading
import time



#创建多线程来执行任务
def create_task(paramsList):
    threadList=[] #设置一个线程列表存储创建的线程
    print "一个有{}个参数".format(len(paramsList)) #打印出构建了多少个请求参数,有多少个参数就代表要执行多少次请求任务
    num=len(paramsList)/50  #每个线程执行50个任务,那需要多少个线程,50可以改变
    print '准备创建{}个线程'.format(num+1) #为防止漏掉任务,在上面结果上线程最好再+1
    for count in range(num+1): #for循环创建线程,同时要为每个线程分配不同的任务
        startParams = paramsList[::50][count] # 按50步长去切割参数列表,可以得到不同切割点的值
        startIndex=paramsList.index(startParams) #获取切割点的起始索引位置
        endIndex= startIndex + 50 #起始索引位置+50,为结束索引为准
        threadParamsList=paramsList[startIndex:endIndex] #根据起点和结束点,为参数列表分配不同任务
        print "已为一个线程分配好参数,有{}个参数".format(len(threadParamsList))
        thread=threading.Thread(target=get_data,args=(threadParamsList,)) #调用get_data方法,并为每个线程传入不同参数
        threadList.append(thread) #将线程添加到线程列表
    for thread in threadList:
        thread.setDaemon(True)  # 设置守护线程
        thread.start()  #开始线程
    for thread in threadList:
        thread.join() #所有子线程结束后再退出



#城市ID和pageNum构建请求参数
def create_params(cityIdList,pageNum):
    paramsList=[]
    for cityId in cityIdList:
        for num in range(1,pageNum+1):
            params={
                'currentPage':num,
                'cityId':cityId,
                'showCount':18
            }
            paramsList.append(params)
    return paramsList

#请求接口获取数据
def get_data(threadParamsList):
    print "当前线程{}在执行任务...".format(threading.current_thread().name)
    #这里的list是用来存储每个线程爬取到的数据,存储完成后,再添加到全局变量list里
    cityIdList = []
    titleList = []
    detailDescList = []
    subTitleList = []
    locationList = []
    showPriceList = []
    labelsList = []
    latList = []
    lngList = []
    url='https://api.mgzf.com/room-find-web/find/list'
    for params in threadParamsList:
        randomTime=random.uniform(1,3) #随机的请求时间间隔,防止被封IP
        time.sleep(randomTime)
        res=requests.post(url,data=params,headers=headers)
        resDict=json.loads(res.text) #将json数据转化为dict类型
        resList=resDict['content']['list']
        labelDataList=[]
        for data in resList:
            #下面是根据返回的数据格式解析到自己想要的数据,这里具体场景具体分析
            cityIdList.append(data['cityId'])
            titleList.append(data['title'])
            detailDescList.append(data['detailDesc'])
            subTitleList.append(data['subTitle'])
            locationList.append(data['location'])
            showPriceList.append(data['showPrice'])
            for labelData in data['labels']: #label数据比较特殊,需要再一次for循环
                labelDataList.append(labelData['title'])
            labelStr=','.join(labelDataList) #拼接获取到标签
            labelDataList=[] #请注意需要清空对应数据,否则拼接的数据会出错
            labelsList.append(labelStr)
            latList.append(data['lat'])
            lngList.append(data['lng'])
    #将每个爬虫获取到的数据添加到全局变量中,请注意这里要用extend,不用append,因为extend是追加列表数据
    cityId.extend(cityIdList)
    title.extend(titleList)
    detailDesc.extend(detailDescList)
    subTitle.extend(subTitleList)
    location.extend(locationList)
    showPrice.extend(showPriceList)
    labels.extend(labelsList)
    lat.extend(latList)
    lng.extend(lngList)
    print "当前线程{}执行任务完成".format(threading.current_thread().name)


#存储数据
def save_data():
    #由于接口返回数据没有城市名称,所以这边要比对所有cityId,从最初设置的cityData中拿到城市名称
       for id in cityId:
        for cityDict in cityData:
            if int(id)==cityDict['cityId']: #id类型需要由unicode转化为int
                cityName.append(cityDict['name'])

    #构建一个字典,每个字段都是一个series,值是列表,方便把数据通过dateframe存储为表格形式
    data={
        'cityName':cityName,
        'cityId':cityId,
        'title':title,
        'detailDesc':detailDesc,
        'subTitle':subTitle,
        'location':location,
        'showPrice':showPrice,
        'labels':labels,
        'lat':lat,
        'lng':lng
    }
    print '开始存储数据,共有{}条数据'.format(len(data['cityId']))
    data=pd.DataFrame(data) #转化为datefram表格数据
    data.to_csv('../数据源/蘑菇租房数据.csv',encoding='utf-8-sig') #存储数据
    print "数据存储完成"




if __name__=='__main__':
    startTime=time.time() #记录程序开始时间,后面用来计算爬虫耗时
    cityData=[
        {
            'name':'上海',
            'cityId':289
        },
        {
            'name': '成都',
            'cityId':75
        },
        {
            'name': '东莞',
            'cityId':119
        },
        {
            'name': '南京',
            'cityId':315
        },
        {
            'name': '合肥',
            'cityId':127
        },
        {
            'name': '北京',
            'cityId':131
        },
        {
            'name': '杭州',
            'cityId':179
        },
        {
            'name': '重庆',
            'cityId':132
        },
        {
            'name': '泉州',
            'cityId':134
        },
        {
            'name': '贵阳',
            'cityId':146
        },
        {
            'name': '长沙',
            'cityId':158
        },
        {
            'name': '宁波',
            'cityId':180
        },
        {
            'name': '厦门',
            'cityId':194
        },
        {
            'name': '武汉',
            'cityId': 218
        },
        {
            'name': '苏州',
            'cityId': 224
        },
        {
            'name': '西安',
            'cityId': 233
        },
        {
            'name': '广州',
            'cityId': 257
        },
        {
            'name': '郑州',
            'cityId': 268
        },
        {
            'name': '济南',
            'cityId': 288
        },
        {
            'name': '福州',
            'cityId': 300
        },
        {
            'name': '天津',
            'cityId': 332
        },
        {
            'name': '深圳',
            'cityId': 340
        }

    ] #通过浏览器审查元素可以得到每个城市的名称和城市ID,城市ID在后面请求接口的时候会用到
    idList=[]
    for city in cityData:
        idList.append(city['cityId']) #从cityData中把城市ID提取出来
    #通用的请求头设置,这里没啥好说的
    headers={
        'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
        'refer':'http://www.mgzf.com/list/',
        'origin':'http://www.mgzf.com',
        'host':'api.mgzf.com',
        'Connection':'keep-alive',
        'Content-Type':'application/x-www-form-urlencoded'
    }

    #因为多线程去爬取数据,所以必须设置一个全局变量用来存储爬到的数据,因为各线程爬到的结果和速度都不一样
    cityId = []
    cityName=[]
    title = []
    detailDesc = []
    subTitle = []
    location = []
    showPrice = []
    labels = []
    lat = []
    lng = []


    page=raw_input("请输入爬取的页数:") #从页面上看,最大页数好像是30,所以输入30差不多
    pageNum=int(page) #输入的是str类型,需要转化为int
    paramsList=create_params(idList,pageNum) #调用构建请求参数方法
    create_task(paramsList) #调用创建多线程的方法
    save_data() #调用存储数据的方法
    endTime=time.time() #程序结束时时间
    print "爬虫结束,共耗时{}".format(endTime-startTime) #打印出整个爬虫的耗时

二、爬取过程和结果


image.png

image.png

三、利用tableau进行数据分析
1、不同城市平均房租
1)可以看到上海,杭州,北京的平均房租排名前,符合预期
2)第一名的平均房租是最后一名郑州的几乎3倍价格,可以想象到一线城市的压力
3)在下钻城市,拿上海举例,其中虹口区房租最贵高达5527,宝山和奉贤由于较为偏远,平均房租稍微便宜了点,而我住的普通平均房租是3515


image.png

image.png

2、不同城市小区词云图
1)筛选上海这座城市,可以看到九亭这边房源数比较多,属于松江区域
2)图上颜色越深代表平均房租越贵,从大概位置上看以虹口徐汇地区为主


image.png

3、不同城市户型分析
1)筛选了一线城市(上海北京杭州)的户型,可以看到以一室一厅一卫为主,说明市场需求以这种一室一厅的整租为主,从价格上3000元也在可接收范围内
2)再看看二三线城市的分布(宁波郑州等),可以看出,户型出租以多居室为住,平均单间价格为900
3)从这2个图可以看出,一二线城市的出租类型差异化还是很大的


image.png

image.png

4、不同城市房子描述分析
1)对于一线城市(比如上海),地铁,中心地段,为主要描述关键词

你可能感兴趣的:(蘑菇租房爬虫数据分析)