蘑菇租房爬虫数据分析

一、先上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)对于一线城市(比如上海),地铁,中心地段,为主要描述关键词

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容