Python爬取北京地区蛋壳公寓数据,并进行数据可视化处理[Python基础]

python

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

 

前言


近期,蛋壳公寓“爆雷”事件持续发酵,期间因拖欠房东房租与租客退款,蛋壳公寓陷入讨债风波,全国多地蛋壳公寓办公区域出现大规模解约事件,而作为蛋壳公寓总部所在地北京,自然首当其冲。

为了应对大规模的解约,北京在全市已经设立了100多个蛋壳公寓矛盾纠纷接待点,包含了蛋壳公寓涉及到的12个区,这些接待点下沉到了街道甚至社区,以方便涉及蛋壳公寓事件的房东和租客咨询和处理纠纷。

长租公寓暴雷,不少年轻人不得不流离失所,构成疫情下的另一个经济写照,事态何去何从,值得关注。本文从数据角度出发,爬取了蛋壳公寓北京区域共6025条公寓数据,清洗数据,并进行可视化分析,为大家了解蛋壳公寓提供一个新的视角。

数据获取

蛋壳公寓网页结构相对简单,数据结构统一,简单的url翻页构造即可。需要注意的是极少数网页会返回404,需要添加判断过滤掉。本文用request请求到数据,用xpath对返回的数据进行解析,最后以追加模式将数据存储为csv文件。爬虫核心代码如下:

def get_danke(href):

time.sleep(random.uniform(0, 1)) #设置延时,避免对服务器产生压力

response = requests.get(url=href, headers=headers)

if response.status_code == 200: #部分网页会跳转404,需要做判断

res = response.content.decode("utf-8")

div = etree.HTML(res)

items = div.xpath("/html/body/div[3]/div[1]/div[2]/div[2]")

for item in items:

house_price=item.xpath("./div[3]/div[2]/div/span/div/text()")[0]

house_area=item.xpath("./div[4]/div[1]/div[1]/label/text()")[0].replace("建筑面积:约","").replace("㎡(以现场勘察为准)","")

house_id=item.xpath("./div[4]/div[1]/div[2]/label/text()")[0].replace("编号:","")

house_type=item.xpath("./div[4]/div[1]/div[3]/label/text()")[0].replace("

","").replace("","").replace("户型:","")

house_floor=item.xpath("./div[4]/div[2]/div[3]/label/text()")[0].replace("楼层:","")

house_postion_1=item.xpath("./div[4]/div[2]/div[4]/label/div/a[1]/text()")[0]

house_postion_2=item.xpath("./div[4]/div[2]/div[4]/label/div/a[2]/text()")[0]

house_postion_3=item.xpath("./div[4]/div[2]/div[4]/label/div/a[3]/text()")[0]

house_subway=item.xpath("./div[4]/div[2]/div[5]/label/text()")[0]

else:

house_price = None

house_area = None

house_id = None

house_type = None

house_floor = None

house_postion_1 = None

house_postion_2 = None

house_postion_3 = None

house_subway = None

......

由于代码运行过程中中断了几次,最终将数据保存为以下几个csv文件中:

 

数据处理

导入数据分析包

import pandas as pd

import numpy as np

from pathlib import Path

import re

导入数据并合并

找到文件夹中的所有csv文件,遍历读取数据,最后用concat方法合并所有数据。

files = Path(r"蛋壳公寓").glob("*.csv")

dfs = [pd.read_csv(f) for f in files]

df = pd.concat(dfs)

df.head()

 

数据去重

数据爬取过程中有中断,因此可能存在重复爬取的情况,需要去重处理。

df = df.drop_duplicates()

查看数据

用df.info()方法查看整体数据信息,结合预览的数据,我们可以很容易发现,价格和面积字段不是数字类型,需要转换处理。楼层字段可以提取出所在楼层和总楼层。

df.info()

<class"pandas.core.frame.DataFrame">

Int64Index:6026 entries, 0 to 710

Data columns (total 9 columns):

# Column Non-Null Count Dtype

--- ------ -------------- -----

0 价格 6025 non-null object

1 面积 6025 non-null object

2 编号 6025 non-null object

3 户型 6025 non-null object

4 楼层 6025 non-null object

5 位置16025 non-null object

6 位置26025 non-null object

7 小区 6025 non-null object

8 地铁 6025 non-null object

dtypes: object(9)

memory usage: 470.8+ KB

数据类型转换

在字段类型转换时报错,检查发现是数据存在一行脏数据,因此先删除脏数据再做转换即可。数据类型转换用到astype()方法,提取所在楼层和总楼层时根据字符"/"分列即可,采用split()方法。

#删除包含脏数据的行

jg = df["价格"] != "价格"

df = df.loc[jg,:]

#将价格字段转为数字类型

df["价格"] = df["价格"].astype("float64")

#将面积字段转为数字类型

df["面积"] = df["面积"].astype("float64")

#提取所在楼层

df = df[df["楼层"].notnull()]

df["所在楼层"]=df["楼层"].apply(lambda x:x.split("/")[0])

df["所在楼层"] = df["所在楼层"].astype("int32")

#提取总楼层

df["总楼层"]=df["楼层"].apply(lambda x:x.split("/")[1])

df["总楼层"] = df["总楼层"].str.replace("","").astype("int32")

地铁字段清洗

地铁字段可以提取出地铁数和距离地铁距离。地铁数通过统计字符"号线”的数量来计算,而距离地铁距离通过正则表达式匹配出字符"米"前面的数字即可。为方便理解,这里直接构造函数进行清洗。

def get_subway_num(row):

subway_num=row.count("号线")

return subway_num

def get_subway_distance(row):

distance=re.search(r"d+(?=米)",row)

if distance==None:

return-1

else:

return distance.group()

df["地铁数"]=df["地铁"].apply(get_subway_num)

df["距离地铁距离"]=df["地铁"].apply(get_subway_distance)

df["距离地铁距离"]=df["距离地铁距离"].astype("int32")

保存数据

数据清洗完毕后,用df.to_excel()将数据保存为excel文件。

df.to_excel(r"蛋壳公寓.xlsx")

df.head()

 

数据可视化

导入可视化相关包

import matplotlib.pyplot as plt

import seaborn as sns

%matplotlib inline

plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置加载的字体名

plt.rcParams["axes.unicode_minus"] = False# 解决保存图像是负号"-"显示为方块的问题

import jieba

from pyecharts.charts import *

from pyecharts import options as opts

from pyecharts.globals import ThemeType

import stylecloud

from IPython.display import Image

各行政区公寓数量

根据清洗后的数据绘制北京蛋壳公寓分布地图,我们可以很清晰的看到蛋壳公寓的布局,朝阳区和通州区是蛋壳公寓主要分布区域,延庆、密云、怀柔、平谷和门头沟地区蛋壳公寓分布极少。

 

从各行政区数量上来看,朝阳区和通州区蛋壳公寓数量均超过1000个,朝阳区遥遥领先其他地区,共计1877个,通州区紧随其后,为1027个。

df7 = df["位置1"].value_counts()[:10]

df7 = df7.sort_values(ascending=True)

df7 = df7.tail(10)

print(df7.index.to_list())

print(df7.to_list())

c = (

Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))

.add_xaxis(df7.index.to_list())

.add_yaxis("",df7.to_list()).reversal_axis() #X轴与y轴调换顺序

.set_global_opts(title_opts=opts.TitleOpts(title="各行政区公寓数量",subtitle="数据来源:蛋壳公寓 ",pos_left = "left"),

xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改横坐标字体大小

yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改纵坐标字体大小

)

.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position="right"))

)

c.render_notebook()

 

小区公寓数量TOP10

从小区数量来看,新建村小区、花香东苑和连心园西区蛋壳公寓数量最多,均超过50个。这也意味着,这些小区的租户受蛋壳风波的影响相较于其他小区更大。

df7 = df["小区"].value_counts()[:10]

df7 = df7.sort_values(ascending=True)

df7 = df7.tail(10)

print(df7.index.to_list())

print(df7.to_list())

c = (

Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK,width="1100px",height="600px"))

.add_xaxis(df7.index.to_list())

.add_yaxis("",df7.to_list()).reversal_axis() #X轴与y轴调换顺序

.set_global_opts(title_opts=opts.TitleOpts(title="小区公寓数量TOP10",subtitle="数据来源:蛋壳公寓 ",pos_left = "left"),

xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=11)), #更改横坐标字体大小

yaxis_opts=opts.AxisOpts(axislabel_opts={"rotate":30}), #更改纵坐标字体大小

)

.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position="right"))

)

c.render_notebook()

 

蛋壳公寓租金分布

对租金进行区间分段,我们发现,北京蛋壳公寓的租金还是相当有吸引力的,超过一半的公寓租金在2000-3000元/月。2000元/月以下的公寓数量占比也高达26.13%。

#租金分段

df["租金分段"] = pd.cut(df["价格"],[0,1000,2000,3000,4000,1000000],labels=["1000元以下","1000-2000元","2000-3000元","3000-4000元","4000元以上"],right=False)

df11 = df["租金分段"].value_counts()

df11 = df11.sort_values(ascending=False)

df11 = df11.round(2)

print(df11)

c = (

Pie(init_opts=opts.InitOpts(theme=ThemeType.DARK))

.add(

"",

[list(z) for z in zip(df11.index.to_list(),df11.to_list())],

radius=["20%", "80%"], #圆环的粗细和大小

rosetype="area"

)

.set_global_opts(legend_opts = opts.LegendOpts(is_show = False),title_opts=opts.TitleOpts(title="蛋壳公寓租金分布",subtitle="数据来源:蛋壳公寓",pos_top="0.5%",pos_left = "left"))

.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%",font_size=16))

)

c.render_notebook()

 

各行政区租金分布

我们继续将地区因素引入租金分析中,发现,不同行政区内的租金分布也存在较大差异。以朝阳区为例,2000-3000元/月的公寓占比最多,而通州区1000-2000元/月的公寓占比更多。这也很容易理解,毕竟所处的区位和经济发展状况差异较大。

h = pd.pivot_table(df,index=["租金分段"],values=["价格"],

columns=["位置1"],aggfunc=["count"])

k = h.droplevel([0,1],axis=1) #删除指定的索引/列级别

c = (

Polar(init_opts=opts.InitOpts(theme=ThemeType.DARK))

.add_schema(angleaxis_opts=opts.AngleAxisOpts(data=k.columns.tolist(), type_="category"))

.add("1000以下",h.values.tolist()[0], type_="bar", stack="stack0")

.add("1000-2000元",h.values.tolist()[1], type_="bar", stack="stack0")

.add("2000-3000元", h.values.tolist()[2], type_="bar", stack="stack0")

.add("3000-4000元", h.values.tolist()[3], type_="bar", stack="stack0")

.add("4000元以上", h.values.tolist()[4], type_="bar", stack="stack0")

.set_global_opts(title_opts=opts.TitleOpts(title="各行政区租金情况",subtitle="数据来源:蛋壳公寓"))

)

c.render_notebook()

 

蛋壳公寓楼层分布

从北京蛋壳公寓的楼层分布来看,10层以下占比高达73.92,高层和超高层不是蛋壳公寓的理想选择。

# 漏斗图 

df["楼层分段"] = pd.cut(df["所在楼层"],[0,10,20,30,40,1000000],labels=["10层以下","10-20层","20-30层","30-40层","40层以上"],right=False)

count = df["楼层分段"].value_counts() # pd.Series

print(count)

job = list(count.index)

job_count = count.values.tolist()

from pyecharts.charts import Funnel

c = (

Funnel(init_opts=opts.InitOpts(theme=ThemeType.DARK))

.add("", [list(i) for i in zip(job,job_count)])

.set_global_opts(

title_opts=opts.TitleOpts(title="蛋壳公寓楼层分布",subtitle="数据来源:蛋壳公寓",pos_top="0.1%",pos_left = "left"),legend_opts = opts.LegendOpts(is_show = False))

.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%",font_size=16))

)

c.render_notebook()

 

蛋壳公寓户型分布

从北京蛋壳公寓的户型分布来看,3室1卫为主,共计2783个,其次才是4室1卫。这与深圳蛋壳公寓以4室1卫为主的情况存在较大差异。

python;gutter:true;">df2 = df.groupby("户型")["价格"].count() 

df2 = df2.sort_values(ascending=False)[:10]

# print(df2)

bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))

bar.add_xaxis(df2.index.to_list())

bar.add_yaxis("",df2.to_list()) #X轴与y轴调换顺序

bar.set_global_opts(title_opts=opts.TitleOpts(title="蛋壳公寓户型分布",subtitle="数据来源:蛋壳公寓",pos_top="2%",pos_left = "center"),

xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改横坐标字体大小

yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改纵坐标字体大小

)

bar.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position="top"))

bar.render_notebook()

  

 

蛋壳公寓面积分布

从北京蛋壳公寓的面积分布来看,86.77%的公寓面积不足20㎡。北京10㎡以下的蛋壳公寓占比达到了21.2%,即便如此,这个数字仍不足深圳的一半。

df["面积分段"] = pd.cut(df["面积"],[0,10,20,30,40,1000000],labels=["10㎡以下","10-20㎡","20-30㎡","30-40㎡","40㎡以上"],right=False)

df2 = df["面积分段"].astype("str").value_counts()

print(df2)

df2 = df2.sort_values(ascending=False)

regions = df2.index.to_list()

values = df2.to_list()

c = (

Pie(init_opts=opts.InitOpts(theme=ThemeType.DARK))

.add("", list(zip(regions,values)))

.set_global_opts(legend_opts = opts.LegendOpts(is_show = False),title_opts=opts.TitleOpts(title="蛋壳公寓面积分布",subtitle="数据来源:蛋壳公寓",pos_top="0.5%",pos_left = "left"))

.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%",font_size=14))

)

c.render_notebook()

 

蛋壳公寓商圈分布

通过对北京几个主要行政区商圈进行词云统计(字体越大表示蛋壳公寓数量最多),朝阳区的管庄、望京,通州区的北关,丰台区的樊羊路、方庄和角门,昌平区的天通苑,海淀区的永丰和西二旗,大兴区的黄村和亦庄,是蛋壳公寓主要选择的商圈。

# 绘制词云图

text1 = get_cut_words(content_series=df1["位置2"])

stylecloud.gen_stylecloud(text="".join(text1), max_words=100,

collocations=False,

font_path=r"C:WINDOWSFONTSMSYH.TTC",

icon_name="fas fa-home",

size=653,

palette="cartocolors.diverging.ArmyRose_2",

output_name="./1.png")

Image(filename="./1.png")

 

相关性分析

从相关系数表可以看出,北京蛋壳公寓的面积、周边地铁数对公寓的价格有较大的的影响,相关系数分别为0.81和0.36。蛋壳公寓在进行房屋定价时,对公寓的面积以及公寓的地铁配套有较大权重的考虑。由于北京蛋壳公寓距离地铁都很近,因此,距离的远近对公寓的价格影响有限。另外,所在楼层也不是北京蛋壳公寓租金高低的重要影响因素。

color_map = sns.light_palette("orange", as_cmap=True)  #light_palette调色板

df.corr().style.background_gradient(color_map)

 

最后,愿所有受蛋壳公寓“暴雷”事件影响的年轻人都能熬过这个寒冬。

以上是 Python爬取北京地区蛋壳公寓数据,并进行数据可视化处理[Python基础] 的全部内容, 来源链接: utcz.com/z/529985.html

回到顶部