深圳租房之旅

深圳租房之旅

最近难菌,利用Python爬取了某個網(wǎng)站上關(guān)于深圳租房的一些信息珠移,獲得了2000*12的數(shù)據(jù)的畴,然后利用pandas及第三方的庫進(jìn)行了數(shù)據(jù)清洗硫眨、分析和可視化的操作足淆,對深圳的租房現(xiàn)狀有了初步分析。

image

聲明:數(shù)據(jù)僅用來學(xué)習(xí),未用作任何商業(yè)用途

數(shù)據(jù)爬取

本次的數(shù)據(jù)是通過爬蟲從網(wǎng)上獲取的巧号。很久沒有爬數(shù)據(jù)了族奢,把以前寫的代碼打開看了下,直接拿過來改了很多需要的信息丹鸿,還是可以直接跑出結(jié)果越走。網(wǎng)站也沒有反爬措施,獲得數(shù)據(jù)蠻順利的

導(dǎo)入各種庫

import pandas as pd
import numpy as np
import plotly as py
import plotly_express as px
from plotly.subplots import make_subplots  # 畫多個圖
import plotly.graph_objects as go
import json
from lxml import etree
import requests
import xlwt
import re
import time

# 顯示所有列
# pd.set_option('display.max_columns', None)
# 顯示所有行
# pd.set_option('display.max_rows', None)
# 設(shè)置value的顯示長度為100靠欢,默認(rèn)為50
# pd.set_option('max_colwidth',100)` 

代碼

代碼中涉及到很多爬蟲中需要用到的知識點(diǎn):

  • 請求頭的設(shè)置
  • xpath的使用
  • 將字典數(shù)據(jù)轉(zhuǎn)成json格式廊敌,json包的使用
  • 數(shù)據(jù)保存到excel中:xlwt的使用
# 本案例僅供學(xué)習(xí)使用,未用作任何商業(yè)用途

class Leyoujia:
  
    # 1. 初始化url和headers
    def __init__(self):
        self.start_url = 'https://shenzhen.leyoujia.com/zf/?n={}'
        self.headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5)  "}   # 需要換成實(shí)際的請求頭
    
    # 2. 得到全部的URL地址
    def get_url_list(self):
        url_list = [self.start_url.format(i) for i in range(101)]   # 構(gòu)造URL地址的列表形式并返回
        return url_list
    
    # 3. 發(fā)送請求门怪,獲取響應(yīng)
    def parse_url(self, url):
        #print("parsing...", url)
        response = requests.get(url=url, headers=self.headers)
        return response.content.decode('utf-8', 'ignore')  # 返回的是解析內(nèi)容
     
    # 4. 獲取數(shù)據(jù)
    def get_content_list(self, html_str):
        html = etree.HTML(html_str)
        div_list = html.xpath("/html/body/div[3]/div[2]/div[1]/div[5]/ul/li")

        content_list = []
        for div in div_list:
                item = {"layout":"","location":"","size":"","sizeInside":"",
                        "zhuangxiu":"","numberFloor":"","time":"","name":"","zone":"",
                        "position":"","way":"","money":""}
                
                item["layout"] = div.xpath(".//div[2]/p[2]/span[1]/text()")
                item["location"] = div.xpath(".//div[2]/p[2]/span[2]/text()")
                item["size"] = div.xpath(".//div[2]/p[2]/span[3]/text()")
                item["sizeInside"] = div.xpath(".//div[2]/p[2]/span[4]/text()")
                
                item["zhuangxiu"] = div.xpath(".//div[2]/p[3]/span[1]/text()")
                item["numberFloor"] = div.xpath(".//div[2]/p[3]/span[2]/text()")
                item["time"] = div.xpath(".//div[2]/p[3]/span[3]/text()")
                item["name"] = div.xpath(".//div[2]/p[4]/span[1]/a/text()")
                item["zone"] = div.xpath(".//div[2]/p[4]/span[2]/a[1]/text()")
                item["position"] = div.xpath(".//div[2]/p[4]/span[2]/a[2]/text()")
                item["money"] = div.xpath(".//div[3]/p[1]/span/text()")
                item["way"] = div.xpath(".//div[3]/p[2]/text()")
                
                content_list.append(item)                     
        return content_list
    
    # 5. 保存數(shù)據(jù)
    def save_content_list(self, content_list):  # content_list是個列表骡澈,列表中的元素是item,item是個字典
        with open("leyoujia.txt", "a", encoding="utf-8") as f :
            for content in content_list:
                f.write(json.dumps(content))
                f.write("\n")
                
    # 6. 數(shù)據(jù)保存到Excel中掷空,使用xlwt(用于寫入Excel中)
    def save_to_excel(self, content_list):
        workbook = xlwt.Workbook(encoding='utf-8')
        sheet = workbook.add_sheet('leyoujia') # 設(shè)置表名
        head = ["name","layout","location","size","sizeInside","zhuangxiu",
                "numberFloor","time","zone","position","money","way"]  # 設(shè)置表頭
        for h in range(len(head)):
            sheet.write(0, h, head[h])

        length=len(content_list)
        for j in range(1,length+1):
            sheet.write(j,0,content_list[j-1]["name"])
            sheet.write(j,1,content_list[j-1]["layout"])
            sheet.write(j,2,content_list[j-1]["location"])
            
            sheet.write(j,3,content_list[j-1]["size"])
            sheet.write(j,4,content_list[j-1]["sizeInside"])
            sheet.write(j,5,content_list[j-1]["zhuangxiu"])
            sheet.write(j,6,content_list[j-1]["numberFloor"])
            sheet.write(j,7,content_list[j-1]["time"])
            sheet.write(j,8,content_list[j-1]["zone"])
            sheet.write(j,9,content_list[j-1]["position"])
            sheet.write(j,10,content_list[j-1]["money"])
            sheet.write(j,11,content_list[j-1]["way"])

        workbook.save('./leyoujia.xls')
        
    def main(self):
        # 獲得url_list
        url_list = self.get_url_list()
        content_lists = []
        # 在url_list中進(jìn)行請求的發(fā)送肋殴,內(nèi)容的獲取以及保存數(shù)據(jù)
        for url in url_list:
            html_str = self.parse_url(url)
            content_list = self.get_content_list(html_str)
            self.save_content_list(content_list)   # 保存content_list
            content_lists.extend(content_list)  # 將所有的content_list全部追加到content_lists
        self.save_to_excel(content_lists)  # 保存到excel中
                        
if __name__ == '__main__':
    time.sleep(1)
    leyoujia = Leyoujia()
    leyoujia.main()

數(shù)據(jù)處理

讀取數(shù)據(jù)

將上面保存的數(shù)據(jù)讀取從本地讀取出來

image

字段含義

"""
name: 小區(qū)的名字
laytou:戶型
location:朝向
size:房子建筑面積大小
sizeInside:套內(nèi)面積大小
zhuangxiu:精裝、豪裝拣帽、普裝疼电、毛坯
numberFloor:樓層數(shù)
time:建成時間
zone:區(qū)
position:所在區(qū)的具體位置
money:價(jià)格
way:出租方式(整租或者合租)
"""

原始數(shù)據(jù)信息

image
image

刪除缺失值

使用的是dropna函數(shù),兩個重要的參數(shù):

  • axis:0表示行减拭,1表示列
  • how:any表示至少有一個缺失值蔽豺,all表示必須全部為缺失值
image

字段處理

為何處理

對于數(shù)據(jù)中的幾個字段,我們需要的只是其中的數(shù)字信息拧粪,所以需要將它們從整個文本中提取出來修陡。

處理方法

根據(jù)表格中文本不同,介紹3種方法:

  • 通過apply函數(shù)
  • 通過正則表達(dá)式來進(jìn)行匹配
  • 通過replace方法進(jìn)行替換

df1 = df.copy()

# 方式1:通過自定義的函數(shù)可霎,傳給apply方法
def apply_size(x):
    return float(x.split("面積")[1].split("㎡")[0])

def apply_sizeInside(x):
    return float(x.split("面積")[1].split("㎡")[0])

def apply_way(x):
    return x.split("|")[0]

def apply_room(x):
    return x.split("室")[0]

df1["sizeInside"] = df1["sizeInside"].apply(apply_sizeInside)
df1["size"] = df1["size"].apply(apply_size)
df1["room"] = df1["layout"].apply(apply_room)   # 增加一列數(shù)據(jù):臥室個數(shù)魄鸦,從layout中分割出來
df1["way"] = df1["way"].apply(apply_way)

# 方式2:獲取文本中的數(shù)據(jù),正則表達(dá)式
df1["numberFloor"] = df1["numberFloor"].map(lambda str:re.findall(r"\d+",str)[0]).astype(dtype="int")     #

# 方式3:將不需要的內(nèi)容替換成空格癣朗,str.replace
df1["time"] = df1["time"].str.replace("年建成","").astype(dtype="int")

df1.head()

處理前后對比

處理前

image

處理后:增加了room字段

image

同時處理后的字段類型也發(fā)生了變化:

image

單個特征可視化

租房方式-way

對租房方式進(jìn)行可視化:從數(shù)據(jù)和圖形可以直接看出來拾因,絕大多數(shù)的人還是選擇整租

image
image

區(qū)域-zone

想對比每個區(qū)的房源出租情況,從數(shù)據(jù)和圖形中看出來:

  • 福田作為CBD旷余,房源最多绢记;其次是龍華和龍崗,2個老工業(yè)區(qū)
  • 南山作為科技中心正卧,緊隨其后
  • 坪山蠢熄、光明、鹽田3個區(qū)比較落后炉旷,房源少
image
image

裝修方式-zhuangxiu

通過不同的裝修方式來分析對比各種房源的數(shù)量签孔。不同的參數(shù)來實(shí)現(xiàn)顏色的變化叉讥;

image
image
image


結(jié)論:房源最多的還是集中在精裝普裝方式上

房子朝向-location

比較房子的朝向來分析對房源數(shù)量的影響。前3名分別是:朝南饥追、朝南北图仓、朝北

image

居室個數(shù)-room

房子里面臥室的個數(shù)對租房的影響,分析不同數(shù)量的占比

image

區(qū)與房價(jià)的關(guān)系

在每個區(qū)的房租價(jià)格肯定是不同的判耕,通過熱力圖來進(jìn)行對比

結(jié)論:南山和福田的房價(jià)整體是偏高的

image
image

裝修風(fēng)格與房租價(jià)格關(guān)系

image

時間與房租價(jià)格

隨著時間的不斷變化透绩,每個區(qū)域的房租價(jià)格也在跟著變化,通過散點(diǎn)圖來觀察每個區(qū)的價(jià)格分布

關(guān)內(nèi)

通過觀察關(guān)內(nèi)的數(shù)據(jù)分布壁熄,可以看到:

  • 南山和福田的整體價(jià)格高于羅湖和鹽田
  • 南山的均價(jià)幾乎在20k左右
  • 鹽田的整體價(jià)格非常低
  • 羅湖的價(jià)格比較平均帚豪,波動較小
image-20200703201131031

關(guān)外

  • 關(guān)外的價(jià)格整體偏低,均價(jià)在10k不到
  • 寶安和龍崗偶爾出現(xiàn)高價(jià)
  • 坪山房價(jià)偏低
image

多特征的可視化

在這里以南山區(qū)進(jìn)行分析

作圖數(shù)據(jù)


# 用于制作小提琴圖
nanshan = df1[df1["zone"] == "南山"]

# 用于制作柱狀圖
nanshan_position = nanshan["position"].value_counts().reset_index().rename(columns={"index":"position","position":"number"})

# 用于餅圖的制作
nanshan_room = nanshan["room"].value_counts().reset_index().rename(columns={"index":"room","room":"number"})

# 用于散點(diǎn)圖的制作
px.scatter(nanshan,x="numberFloor",y="money",color="position",color_continuous_scale='Inferno')

多特征-多圖

position_list = nanshan_position.position.tolist()

fig = make_subplots(rows=2, cols=2,  # 1*2的子圖
                    subplot_titles=("南山區(qū)房源分布","南山區(qū)租房價(jià)格分布"),
                    specs=[[{"type": "xy"}, {"type": "xy"}],  # 每個子圖的類型
                           [{"type": "domain"}, {"type": "xy"}]]
                   )  
# 柱狀圖
fig.add_trace(go.Bar(x=position_list,  # x=nanshan_position.position.tolist()
                     y=nanshan_position.number.tolist(),
                     text=nanshan_position.number.tolist(),   # 文本顯示在外面
                     textposition='outside'
                    ),row=1,col=1)
 
# 小提琴圖
for position in position_list:
    fig.add_trace(go.Violin(x=nanshan['position'][nanshan['position'] == position],
                            y=nanshan['money'][nanshan['position'] == position],
                            name=position,box_visible=True,meanline_visible=True),
                            row=1, col=2
                           )
# 餅圖    
fig.add_trace(go.Pie(labels=nanshan_room.room.tolist(),
                    values=nanshan_room.number.tolist(),
                    textinfo='label+percent',  # 將labels也顯示出來
                    textposition="auto"),    # 信息是否顯示草丧,顯示在哪里狸臣?
             row=2,col=1)

# 折線圖
fig.add_trace(go.Scatter(x=nanshan.numberFloor.tolist(),
                         y=nanshan.money.tolist(),
                         mode='markers+text',
                         marker=dict(size=6,
                                     color=nanshan.money.tolist(),
                                     colorscale="haline"),
                        ),
             row=2,col=2)

# fig.update_traces(textposition="outside")
fig.update_layout(title_text="南山區(qū)租房情況",  # 兩個圖的總標(biāo)題(左上角)
                  height=1000,width=1000,
                  showlegend=False)  # 隱藏右邊的圖例
fig.show()

image

其他區(qū)的數(shù)據(jù)通過類似的方法得到相應(yīng)的圖形

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市昌执,隨后出現(xiàn)的幾起案子烛亦,更是在濱河造成了極大的恐慌,老刑警劉巖懂拾,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煤禽,死亡現(xiàn)場離奇詭異,居然都是意外死亡岖赋,警方通過查閱死者的電腦和手機(jī)檬果,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唐断,“玉大人选脊,你說我怎么就攤上這事×掣剩” “怎么了恳啥?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長丹诀。 經(jīng)常有香客問我钝的,道長,這世上最難降的妖魔是什么铆遭? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任扁藕,我火速辦了婚禮,結(jié)果婚禮上疚脐,老公的妹妹穿的比我還像新娘。我一直安慰自己邢疙,他們只是感情好棍弄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布望薄。 她就那樣靜靜地躺著,像睡著了一般呼畸。 火紅的嫁衣襯著肌膚如雪痕支。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天蛮原,我揣著相機(jī)與錄音卧须,去河邊找鬼。 笑死儒陨,一個胖子當(dāng)著我的面吹牛花嘶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹦漠,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼椭员,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笛园?” 一聲冷哼從身側(cè)響起隘击,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎研铆,沒想到半個月后埋同,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棵红,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年凶赁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窄赋。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡哟冬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出忆绰,到底是詐尸還是另有隱情浩峡,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布错敢,位于F島的核電站翰灾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏稚茅。R本人自食惡果不足惜纸淮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亚享。 院中可真熱鬧咽块,春花似錦、人聲如沸欺税。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亭罪,卻和暖如春瘦馍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背应役。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工情组, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箩祥。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓院崇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親滥比。 傳聞我的和親對象是個殘疾皇子亚脆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355