背景及任务简介
自如作为在长租公寓行业的头部公司,目前已覆盖国内一线城市和部分新一线城市,因其在租房间种类丰富,装修美观,有大量的“管家”形成了线上线下闭环,且租户具有极高粘性。本次任务通过python抓取符合要求的房源进行简单分析,本次抓取数据是以北京市某区域的“通勤找房”为例,获取当前工作地骑行35分钟内的全部房源,并使用脚本语言对数据进行获取及处理。
数据获取
-
业务分析
在自如主页使用地图找房后,通勤时间筛选条件设置后,发现符合条件的房源有三个区,如下图:
-
编码及分析
通过分析,了解到数据交互的流程,并获取到其房源的链接,然后开始着手脚本编写。
首先导入需要的第三方库:
import urllib.request, urllib.error
import json
import pandas as pd
from tqdm.notebook import tqdm
import matplotlib.pyplot as plt
import seaborn as sns
定义数据获取函数:
def getWebData(url):
request = urllib.request.Request(url)
response_json = ""
try:
response = urllib.request.urlopen(request)
response_json = response.read().decode('utf-8')
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
return response_json
获取最大级别的数据:
url_01 = 'http://www.ziroom.com/commute/room/count?min_lng=116.080679&max_lng=116.387109&min_lat=39.768225&max_lat=40.054683&clng=116.233894&clat=39.911605&zoom=0&transport=ride&minute=35'
response_json_01 = getWebData(url_01)
data_list_01 = (json.loads(response_json_01))['data']['regions']
# 转换为dataFrame格式
df_01 = pd.DataFrame(data_list_01)
# 查看符合要求的房源信息
df_01.head()
数据情况如下:
获取到行政区粒度的数据,需要获取更细粒度数据,但是发现无法通过以上获取数据的building_code进行层级关系的深入,再使用找到的商圈粒度链接进行数据获取:
url_02 = 'http://www.ziroom.com/commute/room/count?min_lng=116.235221&max_lng=116.311829&min_lat=39.877173&max_lat=39.948786&clng=116.233894&clat=39.911605&zoom=14&transport=ride&minute=35'
response_json_02 = getWebData(url_02)
data_list_02 = (json.loads(response_json_02))['data']['regions']
# 转换为dataFrame格式
df_02 = pd.DataFrame(data_list_02)
# 查看符合要求的房源信息
print("符合条件房源商圈共 %d 条" % len(df_02))
df_02
数据情况如下:
符合条件的商圈共14个。
直接获取房间信息:
url_residential = 'http://www.ziroom.com/commute/room/list?min_lng=116.069302&max_lng=116.398154&min_lat=39.768125&max_lat=40.054583&clng=116.233728&clat=39.911505&zoom=12&p=1&transport=ride&minute=35'
response_json_residential = getWebData(url_residential)
data_list_residential = (json.loads(response_json_residential))['data']['rooms']
# 转换为dataFrame格式
df_residential = pd.DataFrame(data_list_residential)
# 查看符合要求的房源信息
print("符合条件房源共 %d 条" % len(df_residential))
df_residential
输出信息如下,获取到20条房源信息
20条数据是第一页的房源数据,下面使用循环遍历全部符合条件的房源:
# 清空数据,保留表头
df_residential = df_residential.drop(df_residential.index)
df_residential
# 循环获取房源信息
for i in tqdm(range(1,data_pages+1)):
url_residential = 'http://www.ziroom.com/commute/room/list?min_lng=116.069302&max_lng=116.398154&min_lat=39.768125&max_lat=40.054583&clng=116.233728&clat=39.911505&zoom=12&p='+str(i)+'&transport=ride&minute=35'
response_json_residential = getWebData(url_residential)
data_list_residential = (json.loads(response_json_residential))['data']['rooms']
df_residential_tmp = pd.DataFrame(data_list_residential)
df_residential = pd.concat([df_residential,df_residential_tmp],ignore_index=True,axis=0)
在执行完毕之后,验证数据条数和网站显示的是否一致:
房间的出租方式为按月和按天两种:
查看关注的月租房租金分布:
count 1364.00
mean 3643.68
std 1643.98
min 1790.00
25% 2460.00
50% 2890.00
75% 4790.00
max 11790.00
符合条件的房源中,均价为3643元,最低价格1790元,可见当前房租价格之高!!继续查看房租分布的具体情况:
x = df_residential[df_residential['price_unit']=='/月'].price.value_counts().sort_index().index
y = df_residential[df_residential['price_unit']=='/月'].price.value_counts().sort_index().values
plt.scatter(x, y)
plt.show()
符合条件的房间主要集中分布在2k~6k之间,其中2500左右有一个最高峰值,对初阶打工人相对友好。
再查看附近哪些小区在租房源最多,选择排名前20进行展示:
x = df_residential.resblock_name.value_counts().sort_values(ascending=False).index[1:20]
y = df_residential.resblock_name.value_counts().sort_values(ascending=False).values[1:20]
import pylab as mpl #import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['YouYuan'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
# plt.barh(x, y,align='center')
# plt.show()
plt.rcParams['figure.figsize'] = (8, 12)
sns.barplot(x=y, y=x,orient='h')
plt.title('房源量最多的小区前20') # 纵向展示需要转换x和y的位置
plt.ylabel('小区名称',fontsize=10)
plt.xlabel('房源量')
永乐东区、长安新城、康馨家园三个小区位列前三,最多的永乐东区多达40间在租房源,自如的空置率我们不得而知,但是这些空置房,将极大的拉低自如营收。
再查看每个小区的均价进行租前考察,在这里,对数据进行排序后查看均价最高的小区和最低的5个小区:
price_mean = df_residential[df_residential['price_unit']=='/月'].groupby('resblock_name')[['price']].mean()
price_mean = price_mean.sort_values(by='price',ascending=False)
price_mean=price_mean.reset_index()
plt.rcParams['font.size'] = 14
ax = sns.catplot(data=price_mean.head(20),x='resblock_name',y='price', kind='point', linestyles="-", height=8, aspect=2, color='g')
plt.title('房租均价TOP20小区分布')
plt.xticks(rotation=45);
plt.rcParams['font.size'] = 14
ax = sns.catplot(data=price_mean.tail(20),x='resblock_name',y='price', kind='point', linestyles="-", height=8, aspect=2, color='r')
plt.title('房租均价BOTTOM20小区分布')
plt.xticks(rotation=45);
通过对比高价小区和价格最低的二十个小区,在找房时就可以直接排除掉高价小区,极大节省打工人用来找房的时间,至少多出半天的时间用来加班~
最后,查看通勤距离的分布情况,由于距离数据存在其他文字,首先进行处理,新增加distance列保存距离数据:
#df_residential['distance']
distance_list = []
for i in df_residential.commute_info:
distance_list.append(i.split(',')[0].replace('距上班地点','').replace('公里',''))
distance_tmp = pd.DataFrame(distance_list, columns=['distance'])
df_residential = pd.concat([df_residential,distance_tmp],axis=1)
count 1476.00
mean 4.32
std 1.76
min 0.80
25% 3.50
50% 4.30
75% 5.70
max 7.00
整体来看,符合条件的房源平均距离工作地4.32公里,最大距离为7公里,可见自如在骑行35分钟内的筛选条件下,默认为7公里。
查看距离通勤点距离与价格的相关性:
# 查看距离和价格的关系
plt.figure(figsize=(15,10))
# 将价格单位转化位千
x= list(df_residential['price']/1000)
y= list(df_residential.distance.astype('float'))
plt.scatter(y, x)
plt.xlabel('价格(k)')
plt.ylabel('距离(km)')
plt.show()
从图中并没有直观看出距离与价格的相关性,为了准确可以进一步进行独立性检验。