鏈家房產(chǎn)網(wǎng)站北京二手房數(shù)據(jù)采集與分析_第1頁
鏈家房產(chǎn)網(wǎng)站北京二手房數(shù)據(jù)采集與分析_第2頁
鏈家房產(chǎn)網(wǎng)站北京二手房數(shù)據(jù)采集與分析_第3頁
鏈家房產(chǎn)網(wǎng)站北京二手房數(shù)據(jù)采集與分析_第4頁
鏈家房產(chǎn)網(wǎng)站北京二手房數(shù)據(jù)采集與分析_第5頁
已閱讀5頁,還剩21頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

目錄

1引言1

1.1項目背景1

1.2開發(fā)環(huán)境與工具1

1.2.1Python簡介1

1.2.2Pandas簡介1

1.2.3Pyecharts簡介2

2需求分析2

2.1可行性需求分析2

2.2采集目標功能分析2

2.3關(guān)鍵技術(shù)分析2

2.3.1網(wǎng)絡(luò)爬蟲技術(shù)2

2.3.2文件存取技術(shù)3

2.3.3可視化技術(shù)3

3數(shù)據(jù)采集3

3.1采集頁面分析3

3.2反爬策略分析4

3.3多線程實現(xiàn)6

3.4翻頁實現(xiàn)8

3.5解析房源信息9

3.6保存到j(luò)son文件10

3.7運行爬蟲程序10

4數(shù)據(jù)清洗與處理11

4.1數(shù)據(jù)清洗需求12

4.2數(shù)據(jù)讀取與處理12

4.3數(shù)據(jù)清洗13

4.4數(shù)據(jù)清洗結(jié)果15

5數(shù)據(jù)統(tǒng)計與分析15

I

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

5.1數(shù)據(jù)分析說明15

5.2數(shù)據(jù)展示15

5.2.1統(tǒng)計各區(qū)的房源數(shù)量和平均價格15

5.2.2統(tǒng)計不同朝向與樓層的房源數(shù)量與價格18

5.2.3統(tǒng)計各裝修風格的數(shù)量20

5.2.4統(tǒng)計每年建造的房屋數(shù)量與價格21

5.3綜述23

6小結(jié)23

參考資料24

II

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

鏈家房產(chǎn)網(wǎng)站北京二手房數(shù)據(jù)采集與分析

1引言

北京作為中國的首都和經(jīng)濟中心,房地產(chǎn)市場一直備受關(guān)注。對于購房者

而言,了解房價走勢、房源數(shù)量和房源質(zhì)量是做出購房決策的重要參考因素。

而二手房市場則更加反映了房地產(chǎn)市場的真實情況,因此對于二手房市場的數(shù)

據(jù)采集和分析也具有很大的實用價值。

1.1項目背景

本畢業(yè)設(shè)計的目的是通過采集北京市二手房源數(shù)據(jù),進行數(shù)據(jù)清洗、數(shù)據(jù)

分析和數(shù)據(jù)可視化,以獲取二手房市場的實際情況和趨勢,并為購房者提供決

策支持。在本畢業(yè)設(shè)計中,將使用requests、pandas、pyecharts和json等技

術(shù),同時還要克服反爬蟲措施,確保數(shù)據(jù)的可靠性和準確性。最終的目標是建

立一個完整的二手房市場數(shù)據(jù)分析平臺,為購房者提供全面的市場信息,幫助

他們做出明智的購房決策。

1.2開發(fā)環(huán)境與工具

1.2.1Python簡介

Python是一種簡單易學、功能強大的編程語言,廣泛應用于數(shù)據(jù)處理、人

工智能、Web開發(fā)等領(lǐng)域。Python具有清晰簡潔的語法結(jié)構(gòu),使得編寫代碼變

得更加高效和愉悅。它擁有大量優(yōu)秀的第三方庫和工具,如numpy、pandas、

matplotlib等,可以方便地處理各種數(shù)據(jù)分析、可視化等任務。同時,Python

社區(qū)非?;钴S,各種問題可以很容易地找到解決方案和支持。Python語言已經(jīng)

成為許多人的首選編程語言,尤其是在數(shù)據(jù)科學和人工智能領(lǐng)域。

1.2.2Pandas簡介

Pandas是一種開源的Python數(shù)據(jù)處理庫,它是基于NumPy的擴展庫,可

以用來處理各種數(shù)據(jù)格式,如CSV、Excel、SQL、JSON等。它提供了DataFrame

和Series這兩個主要的數(shù)據(jù)結(jié)構(gòu),可以靈活地進行數(shù)據(jù)清洗、預處理、轉(zhuǎn)換、

分析等操作。Pandas非常適合數(shù)據(jù)科學領(lǐng)域的工作,包括數(shù)據(jù)清洗和數(shù)據(jù)可視

化等任務。它的操作方式簡單易學,是數(shù)據(jù)分析和機器學習的必備工具之一。

1

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

1.2.3Pyecharts簡介

Pyecharts是一款基于Python語言的數(shù)據(jù)可視化庫,它能夠幫助用戶通過

簡單的代碼實現(xiàn)各種圖表的繪制。該庫內(nèi)置了多種類型的圖表,包括折線圖、

柱狀圖、散點圖、餅圖等,并且支持對圖表的樣式、主題、數(shù)據(jù)等進行靈活的

定制。使用Pyecharts可以快速生成美觀、直觀的數(shù)據(jù)可視化圖表,是Python

數(shù)據(jù)分析領(lǐng)域不可或缺的工具之一。

2需求分析

2.1可行性需求分析

1)技術(shù)可行性分析:

數(shù)據(jù)采集和分析是Python語言的優(yōu)勢之一,利用Python的requests庫和

BeautifulSoup庫可以輕松地從網(wǎng)頁中爬取所需信息,使用Pandas庫可以方便

地處理數(shù)據(jù)。此外,使用pyecharts庫可以將數(shù)據(jù)可視化展示,為后續(xù)分析提

供便利。

2)經(jīng)濟可行性分析:

房地產(chǎn)市場是一個龐大的市場,其信息變化十分迅速,對于中介機構(gòu)和房

產(chǎn)公司而言,獲取市場信息非常重要。通過本項目,可以快速地獲取北京地區(qū)

的二手房源數(shù)據(jù),并對數(shù)據(jù)進行分析,提高市場分析的效率和準確性,降低信

息收集的成本。因此,本項目具有較高的經(jīng)濟可行性。

2.2采集目標功能分析

通過網(wǎng)絡(luò)爬蟲技術(shù)獲取二手房源的相關(guān)信息,包括房源名稱、位置、面積、

價格、房型、樓層、朝向等。將采集的數(shù)據(jù)存儲到j(luò)son文件中,方便后續(xù)的數(shù)

據(jù)處理和分析。對清洗后的數(shù)據(jù)進行分析,探索二手房源市場的價格走勢、房

源分布情況、不同地區(qū)房價等信息。

2.3關(guān)鍵技術(shù)分析

2.3.1網(wǎng)絡(luò)爬蟲技術(shù)

網(wǎng)絡(luò)爬蟲是一種自動化程序,通過模擬用戶訪問行為,自動訪問互聯(lián)網(wǎng)上

的網(wǎng)站,并獲取網(wǎng)站的數(shù)據(jù)。爬蟲通常會遵守網(wǎng)站的協(xié)議和規(guī)則,如robots.txt

2

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

文件,避免對目標網(wǎng)站造成過大的負擔或損害。爬蟲技術(shù)可以廣泛應用于數(shù)據(jù)

采集、信息分析、搜索引擎、機器學習等領(lǐng)域。

2.3.2文件存取技術(shù)

JSON是一種輕量級的數(shù)據(jù)交換格式,易于閱讀和編寫,同時也易于機器解

析和生成。它基于JavaScript語法,但可用于多種編程語言。JSON數(shù)據(jù)結(jié)構(gòu)

包含鍵值對,可以表示數(shù)字、字符串、布爾值、數(shù)組和對象等數(shù)據(jù)類型。在Web

開發(fā)中,JSON常用于前后端數(shù)據(jù)傳輸和API接口的設(shè)計。

2.3.3可視化技術(shù)

可視化技術(shù)是一種將數(shù)據(jù)轉(zhuǎn)化為圖形化界面以便更直觀地展示數(shù)據(jù)的技

術(shù)。它可以幫助人們更好地理解數(shù)據(jù),從而更好地做出決策??梢暬夹g(shù)可以

使用各種圖形圖表,例如柱狀圖、折線圖、散點圖等等,同時還可以使用各種

顏色、標簽和交互方式來使數(shù)據(jù)更加生動和易于理解。常用的可視化工具包括

matplotlib、pyecharts、plotly等等。

3數(shù)據(jù)采集

3.1采集頁面分析

通過瀏覽器打開鏈家網(wǎng)官網(wǎng)/ershoufang/,該網(wǎng)

站可以查詢到北京全境的二手房信息,每頁顯示30條房源信息,選擇欄中可以

篩選北京某個區(qū)的二手房源。鏈家網(wǎng)首頁如下圖3-1所示:

圖3-1鏈家網(wǎng)首頁

3

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

本次數(shù)據(jù)采集的字段有房源名稱、房源所在區(qū)、地址、戶型、朝向、樓層、

建造年份、關(guān)注人數(shù)、發(fā)布時間、總價、每平米價格等。如下圖3-2所示:

圖3-2房源各個字段

其中“房源所在區(qū)“字段沒有直接顯示在房源標簽html文檔中,需要通過

區(qū)域篩選欄選擇不同的區(qū),在對各個區(qū)域發(fā)起請求時保存“房源所在區(qū)”字段。

每個區(qū)的名稱和url保存在html中,如下圖3-3所示:

圖3-3北京各個區(qū)的名稱和url

在篩選欄中選擇“東城”并確認,頁面返回了東城所有的二手房源信息和

總套數(shù),根據(jù)二手房源總套數(shù)和每頁只顯示30條記錄的策略可以確定總頁數(shù),

從而制定頁面翻頁邏輯。如下圖3-4所示:

圖3-4每個區(qū)域二手房總套數(shù)

根據(jù)上述采集頁面的分析,現(xiàn)在已經(jīng)基本確定了頁面采集的方式和流程,

首先對首頁發(fā)起get請求,從響應中解析出北京每個區(qū)的名稱和url,并逐個

對各個區(qū)進行處理,在處理時保存各個區(qū)的名稱;根據(jù)每個區(qū)的二手房源總套

數(shù)計算總頁數(shù),進而進行翻頁處理。

3.2反爬策略分析

對網(wǎng)站進行初步分析發(fā)現(xiàn),該網(wǎng)站的數(shù)據(jù)量比較大,如果在爬蟲程序中沒

有制定合理的反爬策略就很難全量采集到二手房源數(shù)據(jù)。Ip封禁是大多數(shù)網(wǎng)站

常用并且有效的反爬策略,如果同一個ip在短時間內(nèi)對網(wǎng)站發(fā)起了大量的請

4

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

求,該網(wǎng)站就會認為這是爬蟲程序,從而封禁此ip。通過大量的測試發(fā)現(xiàn)該網(wǎng)

站存在封ip的情況,大量請求之后網(wǎng)站會彈出人機驗證頁,如下圖3-5所示:

圖3-5人機認證頁

出現(xiàn)這種情況需要立馬更換ip才能繼續(xù)發(fā)起請求。本項目使用ip代理更

換ip,首先需要到快代理網(wǎng)站申請一個代理api鏈接,對這個代理api每發(fā)起

一次請求就會返回一個新的ip地址,然后在使用這個ip地址即可。如下圖3-6

所示:

圖3-6申請代理api鏈接

在爬蟲程序中在對目標url發(fā)起請求時就不能直接使用requests.get方法

了。需要封裝一個change_ip_request方法,該方法首先對目標url發(fā)起請求,

判斷響應內(nèi)容,如果響應內(nèi)容中包含了”人機驗證”就使用代理api更換ip地

址重新對目標url發(fā)起請求,該方法的返回response對象,以供后續(xù)方法調(diào)用

和解析response。change_ip_request方法如下所示:

5

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

#如果ip被封,則更換新ip繼續(xù)請求

defchange_ip_request(self,url):

headers={'User-Agent':random.choice(self.USER_AGENTS)}

response=requests.get(url,headers=headers,verify=True)

if"人機認證"inresponse.text:

#使用ip代理

ip=

requests.get('/api/getdps/?secret_id=ovczrvb9z9lhk3oayy5j&num=1&signat

ure=omshi1knto9n2i40rsk47gq9ps&pt=1&sep=1')

proxies={'http':'http://'+ip.text}

print("更換ip地址"+str(ip.text)+"")

response=requests.get(url,headers=headers,proxies=proxies,verify=True)

print(response.text)

returnresponse

通過大量測試發(fā)現(xiàn),僅僅只更換ip地址是不能突破網(wǎng)站限制的,還需要隨

機更換請求頭。在爬蟲代碼中構(gòu)建了一個請求頭列表池,在使用requests發(fā)起

請求隨機到池中選址一個請求頭,這樣才能保證爬蟲能夠正常運行。請求頭列

表池如下所示:

def__init__(self):

self.USER_AGENTS=[

"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,

likeGecko)Chrome/58.0.3029.110Safari/537.36Edge/16.16299",

"Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,like

Gecko)Chrome/50.0.2661.102Safari/537.36",

"Mozilla/5.0(WindowsNT6.1;WOW64;rv:54.0)Gecko/20100101Firefox/54.0",

"Mozilla/5.0(Macintosh;IntelMacOSX10_12_6)AppleWebKit/537.36

(KHTML,likeGecko)Chrome/61.0.3163.100Safari/537.36",

"Mozilla/5.0(Macintosh;IntelMacOSX10_12_6)AppleWebKit/604.1.38

(KHTML,likeGecko)Version/11.0Safari/604.1.38",

"Mozilla/5.0(X11;Ubuntu;Linuxx86_64;rv:55.0)Gecko/20100101

Firefox/55.0",

"Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,like

Gecko)Chrome/61.0.3163.79Safari/537.36"]

3.3多線程實現(xiàn)

為了提高數(shù)據(jù)采集的效率,在程序中使用了多線程。Python多線程是指在

一個Python進程中同時運行多個線程,每個線程執(zhí)行不同的任務,以達到并發(fā)

執(zhí)行的效果。在Python中可以通過使用threading模塊來創(chuàng)建多線程。該模

塊提供了一個Thread類,可以通過創(chuàng)建該類的實例來創(chuàng)建線程。

6

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

在開啟多線程之前需要拿到北京各個區(qū)的url鏈接,而后對每個區(qū)開啟一

個線程。使用get_area_items方法獲取每個區(qū)的名稱url鏈接。詳細代碼如下

所示:

defget_area_items(self,start_url):

response=self.change_ip_request(start_url)

html=etree.HTML(response.text)

area_items=html.xpath('/html/body/div[3]/div/div[1]/dl[2]/dd/div[1]/div/a')

method=lambdax:{'area':x.xpath('./text()')[0],'url':''+

x.xpath('./@href')[0]}

area_items_dic=list(map(method,area_items))

print(area_items_dic)

self.request_area(area_items_dic)

首先使用xpath方法獲取到每個區(qū)所在的a標簽列表,在使用map方法和

lambda表達式處理a標簽,將區(qū)名稱和區(qū)url以字段的方式保存到列表中,最

后調(diào)用request_area方法以多線程的方法分別對各個區(qū)進行處理。多線程處理

方法如下所示:

defrequest_area(self,area_items_dic):

Thread=[]

forarea_iteminarea_items_dic:

area=area_item['area']

url=area_item['url']

#創(chuàng)建線程

t1=threading.Thread(target=self.next_page,args=(url,area,1,))

Thread.append(t1)

#開啟所有線程

fortinThread:

t.start()

#等待結(jié)束所有線程

fortinThread:

t.join()

具體來說,該函數(shù)接受一個包含地區(qū)和對應鏈接的字典列表

area_items_dic,遍歷列表中每個字典元素,獲取地區(qū)和鏈接,并為每個地區(qū)

創(chuàng)建一個線程進行爬取。在循環(huán)中,使用threading.Thread()方法創(chuàng)建一個

線程對象t1,并將self.next_page()方法作為目標函數(shù)傳入,同時也將url、

area和1作為參數(shù)傳入。這個1是當前的頁數(shù),該參數(shù)可以方便后續(xù)翻頁的

處理。接著將線程對象t1添加到Thread列表中。這樣,每次循環(huán)都會創(chuàng)建

一個線程,并將其添加到列表中。

7

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

在循環(huán)結(jié)束后,使用for循環(huán)遍歷Thread列表,對其中的每個線程對象

調(diào)用start()方法,以開啟所有線程,使它們并發(fā)執(zhí)行。接著,再次使用for

循環(huán)遍歷Thread列表,并對其中的每個線程對象調(diào)用join()方法,以等待

所有線程執(zhí)行完畢,確保所有線程的爬取任務都已經(jīng)完成。

3.4翻頁實現(xiàn)

函數(shù)next_page(),它實現(xiàn)了在鏈家網(wǎng)站中爬取指定區(qū)域的房產(chǎn)數(shù)據(jù),并

實現(xiàn)了翻頁功能。具體來說,該函數(shù)接收三個參數(shù):url、area和page,其中

url表示該區(qū)域的鏈接,area表示該區(qū)域的名稱,page表示當前爬取的頁數(shù)。

詳細代碼如下所示:

defnext_page(self,url,area,page):

response=self.change_ip_request(url+'/pg'+str(page))

print(response.url)

html=etree.HTML(response.text)

max_page_num=

int(''.join(html.xpath('//*[@id="content"]/div[1]/div[2]/h2/span/text()')))/30

self.get_house_detail(response,area)

ifpage<=max_page_num+1:

print("======正在采集"+area+"的數(shù)據(jù),第"+str(page)+"頁

======")

page+=1

self.next_page(url,area,page)

該函數(shù)首先通過self.change_ip_request()方法發(fā)送請求,并使用

etree.HTML()方法解析HTML頁面。接著,通過XPath表達式獲取該區(qū)域的

最大頁數(shù)max_page_num,并使用self.get_house_detail()方法對該頁的房

產(chǎn)數(shù)據(jù)進行采集。如果當前頁數(shù)page小于等于最大頁數(shù)max_page_num+1,

則將page加1,然后遞歸調(diào)用next_page()方法,以繼續(xù)爬取該區(qū)域的下一

頁數(shù)據(jù)。

需要注意的是,由于遞歸調(diào)用會導致函數(shù)的棧幀不斷增加,因此在爬取大

量數(shù)據(jù)時,可能會出現(xiàn)棧溢出的情況。為了避免這種情況的發(fā)生,可以考慮使

用非遞歸的方式實現(xiàn)翻頁功能,或者使用尾遞歸優(yōu)化等技術(shù)來減少函數(shù)調(diào)用的

棧幀使用。此外,在爬取數(shù)據(jù)時,還需要注意處理可能出現(xiàn)的異常情況,例如

網(wǎng)絡(luò)連接失敗、HTML頁面解析失敗等情況。

8

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

3.5解析房源信息

使用get_house_detail()方法解析鏈家網(wǎng)的二手房源數(shù)據(jù),并將數(shù)據(jù)保存

到文件中。具體來說,該函數(shù)接收兩個參數(shù):response和area,其中response

表示從鏈家網(wǎng)站中獲取到的HTTP響應對象,area表示該區(qū)域的名稱。詳細代

碼如下所示:

defget_house_detail(self,response,area):

html=etree.HTML(response.text)

house_items=html.xpath('//*[@id="content"]/div[1]/ul/li')

result={}

forhouse_iteminhouse_items:

house_name=house_item.xpath('./div[1]/div[1]/a/text()')

address1=house_item.xpath('./div[1]/div[2]/div/a[1]/text()')

address2=house_item.xpath('./div[1]/div[2]/div/a[2]/text()')

house_info=house_item.xpath('./div/div[3]/div/text()')

follow_info=house_item.xpath('./div/div[4]/text()')

price_all=house_item.xpath('.//div[@class="priceInfo"]/div/span/text()')

price_unit=house_item.xpath('.//div[@class="priceInfo"]/div[2]/span/text()')

result['house_name']=''.join(house_name)

result['area']=area

result['address1']=''.join(address1)

result['address2']=''.join(address2)

result['house_info']=''.join(house_info)

result['follow_info']=''.join(follow_info)

result['price_all']=''.join(price_all)

result['price_unit']=''.join(price_unit)

print(result)

self.saveData(result)

該函數(shù)首先使用etree.HTML()方法解析HTML頁面,并使用XPath表達

式獲取到該頁面中所有的房產(chǎn)數(shù)據(jù)。然后,使用循環(huán)遍歷每一個房產(chǎn)數(shù)據(jù),通

過XPath表達式獲取該房產(chǎn)的各個屬性,例如房屋名稱、地址、房屋信息、關(guān)

注信息、總價和單價等。接著,將這些屬性組成一個字典result,并打印輸出

該字典,以方便調(diào)試和查看數(shù)據(jù)。最后,將該字典保存到文件中,通過

self.saveData()方法實現(xiàn)。

需要注意的是,由于鏈家網(wǎng)站的HTML頁面結(jié)構(gòu)可能會發(fā)生變化,因此需

要定期更新XPath表達式,以保證程序能夠正確地獲取房產(chǎn)數(shù)據(jù)。此外,在爬

取數(shù)據(jù)時,還需要注意處理可能出現(xiàn)的異常情況,例如XPath解析失敗、字典

9

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

保存失敗等情況。

3.6保存到j(luò)son文件

將獲取到的數(shù)據(jù)使用saveData方法保存到j(luò)son文件中。具體來說,該函

數(shù)接收一個參數(shù)result,該參數(shù)表示獲取到的單個房產(chǎn)數(shù)據(jù),是一個Python

字典類型。詳細代碼如下所示:

defsaveData(self,result):

json_str=json.dumps(result,ensure_ascii=False)

withopen("house.json","a",encoding="utf-8")asf:

f.write(json_str+"\n")

該函數(shù)首先使用json.dumps()方法將該字典轉(zhuǎn)換成JSON字符串,設(shè)置

ensure_ascii=False參數(shù)可以保證輸出的JSON中文字符不會被轉(zhuǎn)義。然后,

使用withopen()語句打開文件house.json,將JSON字符串寫入文件中。

由于爬取到的數(shù)據(jù)可能很大,因此使用追加模式"a",每次將數(shù)據(jù)添加到文件

的末尾,而不是覆蓋之前的數(shù)據(jù)。需要注意的是,在保存數(shù)據(jù)時,還需要考慮

異常處理和線程安全的問題。例如,當寫入文件時出現(xiàn)異常,需要進行錯誤處

理,以避免程序崩潰。此外,由于多個線程可能會同時訪問同一個文件,因此

需要確保寫入文件時的線程安全性,可以使用鎖機制或者將寫入文件的操作放

在同步塊中,以保證每次只有一個線程能夠?qū)懭胛募?/p>

3.7運行爬蟲程序

使用run方法啟動爬蟲,將url傳入給get_area_items方法。詳細代碼如

下所示:

defrun(self,start_url):

self.get_area_items(start_url)

Main方法如下所示:

if__name__=='__main__':

spider=Spider()

spider.run('/ershoufang/')

程序運行日志如下圖3-7所示:

10

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

圖3-7程序運行日志

程序運行結(jié)束之后會在當前路徑下生成house.json文件,打開文件可以發(fā)

現(xiàn)已經(jīng)采集了2萬4千多條記錄,已經(jīng)滿足了數(shù)據(jù)分析與可視化的要求。如下

圖3-8所示:

圖3-8house.json文件

本項目json作為數(shù)據(jù)傳輸和處理格式,具有以下優(yōu)點:易于解析:JSON是

一種基于文本的格式,易于解析和處理。Python中可以使用json模塊解析和

生成JSON格式數(shù)據(jù),操作簡單;結(jié)構(gòu)化:JSON格式可以表示復雜的數(shù)據(jù)結(jié)構(gòu);

可讀性好:JSON數(shù)據(jù)的格式結(jié)構(gòu)非常清晰,易于閱讀和理解;支持多種編程語

言:由于JSON是一種開放的數(shù)據(jù)格式,支持多種編程語言。因此,JSON數(shù)據(jù)

可以輕松地在不同的系統(tǒng)之間進行交換和共享,實現(xiàn)數(shù)據(jù)的互通性。

4數(shù)據(jù)清洗與處理

數(shù)據(jù)清洗是數(shù)據(jù)預處理中重要的步驟之一,它是指對原始數(shù)據(jù)進行篩選、

整理、轉(zhuǎn)換、填充等一系列操作,以達到消除數(shù)據(jù)噪聲、提高數(shù)據(jù)質(zhì)量、減少

數(shù)據(jù)冗余、適應數(shù)據(jù)分析模型等目的的過程。數(shù)據(jù)清洗可以使得數(shù)據(jù)更加規(guī)整,

更符合數(shù)據(jù)分析模型的要求,有利于進行數(shù)據(jù)挖掘等任務,從而挖掘出更多有

價值的信息。綜上所述,數(shù)據(jù)清洗是數(shù)據(jù)預處理中至關(guān)重要的一個環(huán)節(jié),可以

提高數(shù)據(jù)質(zhì)量、減少冗余、適應分析模型等,從而幫助我們更好地挖掘數(shù)據(jù)背

后的價值。本項目數(shù)據(jù)清洗使用Python中的numpy和pandas庫進行處理。

11

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

4.1數(shù)據(jù)清洗需求

1)使用pandas庫的read_json()函數(shù)讀取house.json文件

2)從house_info字段中解析出戶型、面積、朝向、裝修風格、樓層、建造年

份、建筑結(jié)構(gòu)。將樓層拆分成兩個字段樓層和具有樓層,如“低樓層(共11

層)“處理后為兩個字段”低樓層“和”11“。剔除建造年份字段中多余

的字符串,如“1991年建“處理后”1991“,如果house_info字段中沒有

建造年份則用“0000“代替。

3)從follow_info字段中解析出關(guān)注人數(shù)、發(fā)布天數(shù),剔除其中多余的字符

串,比如“1人關(guān)注”處理后“1”。然后根據(jù)發(fā)布天數(shù)計算出發(fā)布日期。

4)由于price_all字段是房屋的總價,而該字段的單位是“元/平”,明顯單

位存在問題,所以將“元/平”替換成“萬”。

4.2數(shù)據(jù)讀取與處理

創(chuàng)建check_json_file,用于讀取一個JSON文件,并檢查文件中每個JSON

對象的格式。函數(shù)的作用是讀取JSON文件中的數(shù)據(jù),并將格式正確的數(shù)據(jù)轉(zhuǎn)換

為DataFrame格式。在讀取JSON文件的過程中,函數(shù)會跳過格式不正確的數(shù)據(jù)。

如果某個JSON對象的格式正確,那么該對象將被添加到一個列表中,并最終轉(zhuǎn)

換為DataFrame格式返回。

defcheck_json_file(input_file):

#用于存儲格式正確的json數(shù)據(jù)

json_data_list=[]

#打開輸入文件

withopen(input_file,'r',encoding='utf-8')asf:

forlineinf:

try:

#將每一行json數(shù)據(jù)轉(zhuǎn)換成python對象

json_data=json.loads(line.strip())

if'年建'notinjson_data['house_info']:

house_info_li=str(json_data['house_info']).split('|')

structure=house_info_li[-1]

house_info_pre=house_info_li[:-1]

12

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

house_info_pre.append("0000年建")

house_info_pre.append(structure)

json_data['house_info']='|'.join(house_info_pre)

#檢查json數(shù)據(jù)格式是否正確

if'house_name'injson_dataand'area'injson_dataand'address1'injson_data

and'address2'injson_dataand'house_info'injson_dataand'follow_info'injson_dataand

'price_all'injson_dataand'price_unit'injson_data:

#將格式正確的json數(shù)據(jù)添加到列表中

json_data_list.append(json_data)

except:

#如果轉(zhuǎn)換失敗或者格式不正確則跳過該行數(shù)據(jù)

pass

#將列表中的json數(shù)據(jù)轉(zhuǎn)換成DataFrame格式

df=pd.DataFrame(json_data_list)

returndf

該函數(shù)還有一個重要功能,就是處理house_info中的房屋建造年份字段。

House_info字段有兩種格式,第一種包含了房屋建造年份字段,而第二種沒有

包含,在后續(xù)使用pandas清洗數(shù)據(jù)時,這兩種情況需要編寫兩個不同的正則表

達式,這兩個正則表達式不能同時被應用,用其他方式處理也及其復雜。所有

在讀取house.json文件時就將house_info字段的長度統(tǒng)一。

統(tǒng)一house_info字段長度的具體邏輯如下:首先檢查JSON對象中名為

"house_info"的字符串是否包含"年建"這個子字符串。如果不包含,代碼將使

用"|"字符作為分隔符,將"house_info"字段拆分為一個列表。然后,代碼將獲

取列表中的最后一個元素,并將其賦值給變量"structure"。接下來,代碼將創(chuàng)

建一個新的"house_info_pre"列表,該列表包含原始列表中除了最后一個元素

之外的所有元素,并在末尾添加了一個字符串"0000年建",然后將

"structure"變量添加到列表的末尾。最后,代碼將使用"|"字符將新的

"house_info_pre"列表合并成一個字符串,并將其賦值回JSON對象的

"house_info"字段。

4.3數(shù)據(jù)清洗

本項目數(shù)據(jù)清洗主要使用pandas來完成。Pandas是一個開源的Python數(shù)

13

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

據(jù)分析庫,提供了靈活高效的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)分析工具,非常適合進行數(shù)據(jù)清

洗和預處理。

創(chuàng)建data_clean方法并傳入Dataframe對象,讀取Dataframe的house_info

列,從其中解析出戶型、面積、朝向、裝修風格、樓層、建造年份、建筑結(jié)構(gòu)

字段,編寫正則表達式并使用str.extract()函數(shù)從字符串列中提取特定的信

息。詳細代碼如下所示:

str_contain_year='(\d+室\d+廳)\|([\d.]+)平米\|(.+)\|([^]+)\|(.+)\|(\d+)年建\|(.+)'

li_contain_year=['type','size','direction','decoration','floor','year','structure']

df[li_contain_year]=df['house_info'].str.extract(str_contain_year)

df=df.drop('house_info',axis=1)

將樓層字段拆分成兩個字段:floor_level和floor_all,并刪除原有的樓

層字段;清洗"year"字段中的冗余字符串"年建";從follow_info字段中解析

出關(guān)注人數(shù)、發(fā)布天數(shù)。詳細代碼如下所示:

#將樓層拆分成兩個字段樓層和具有樓層

df[['floor_level','floor_all']]=df['floor'].str.extract('(.+)\(共(\d+)層\)')

df=df.drop('floor',axis=1)

#剔除建造年份字段中多余的字符串

df['year']=df['year'].apply(lambdax:re.sub(r'年建','',x)iftype(x)==strelse'0000')

#從follow_info字段中解析出關(guān)注人數(shù)、發(fā)布天數(shù)

df[['follow_num','post_time']]=df['follow_info'].str.extract('(\d+)人關(guān)注/([^]+)發(fā)布')

df=df.drop('follow_info',axis=1)

根據(jù)發(fā)布天數(shù)計算出發(fā)布日期;將price_all字段的單位由“元/平”替換

成“萬”。最后將清洗后的數(shù)據(jù)保存到j(luò)son文件中。詳細代碼如下所示:

#根據(jù)發(fā)布天數(shù)計算出發(fā)布日期

df['post_date']=df['post_time'].apply(calculate_date)

#將price_all字段的單位由“元/平”替換成“萬”

df['price_all']=df['price_all'].str.replace('元/平','萬')

df['price_unit']=df['price_unit'].str.replace('元/平','元')

#將清洗后的數(shù)據(jù)保存為house_clean.json

df.to_json('house_clean.json',orient='records',lines=True,force_ascii=False)

14

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

4.4數(shù)據(jù)清洗結(jié)果

運行check_json_file方法和data_clean方法進行數(shù)據(jù)清洗。代碼如下所

示:

df=check_json_file('house.json')

data_clean(df)

程序運行結(jié)束之后會到本地創(chuàng)建一個house_clean.json文件,其文件內(nèi)容

如下圖所示:

圖4-1數(shù)據(jù)清洗結(jié)果

從數(shù)據(jù)清洗結(jié)果文件中可以看到house_info字段和floor字段被正確解析

了。后續(xù)通過pandas讀取該文件即可進行數(shù)據(jù)的統(tǒng)計與分析。

5數(shù)據(jù)統(tǒng)計與分析

5.1數(shù)據(jù)分析說明

數(shù)據(jù)分析使用pandas來完成,Pandas是一個Python數(shù)據(jù)處理庫,它提供

了高性能、易于使用的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)分析工具,能夠輕松處理各種數(shù)據(jù)類型

和來源,是Python生態(tài)系統(tǒng)中的一個重要組成部分。Pandas提供了一系列數(shù)

據(jù)分析函數(shù),可以幫助用戶對數(shù)據(jù)進行統(tǒng)計分析、聚合操作等。比如,用戶可

以使用groupby()函數(shù)對數(shù)據(jù)進行分組操作;使用describe()函數(shù)對數(shù)據(jù)進行

基本統(tǒng)計分析;使用apply()函數(shù)對數(shù)據(jù)進行自定義操作等。

5.2數(shù)據(jù)展示

5.2.1統(tǒng)計各區(qū)的房源數(shù)量和平均價格

讀取一個名為"house_clean.json"的JSON文件,并將其中的房源數(shù)據(jù)

轉(zhuǎn)換為一個PandasDataFrame對象。對DataFrame進行一些數(shù)據(jù)清洗操作,

15

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

如將'price_unit'字段中的單位“元”去除,并將其中的逗號替換為小數(shù)點。

對'area'字段進行分組統(tǒng)計,得到每個區(qū)域的房源數(shù)量和平均單價。使用

pyecharts庫中的Map類創(chuàng)建一個地圖對象,將房源數(shù)量和平均單價數(shù)據(jù)分別

添加到地圖上。設(shè)置地圖的全局選項,如標題、視覺映射選項等。最后將地圖

保存為一個HTML文件。詳細代碼如下所示:

importjson,re

importpandasaspd

frompyecharts.chartsimportMap

frompyechartsimportoptionsasopts

#讀取JSON文件

withopen('house_clean.json','r',encoding='gbk')asf:

houses=[json.loads(line)forlineinf.readlines()]

#轉(zhuǎn)換為DataFrame

df=pd.DataFrame(houses)

df['price_unit']=df['price_unit'].map(lambdax:float(str(x).replace('元','').replace(',','.')))

#根據(jù)area字段分組統(tǒng)計house_name的數(shù)量和price_unit的平均價格

result=df.groupby('area').agg({'house_name':'count','price_unit':'mean'}).reset_index()

result.columns=['area','count','mean_price_unit']

result['mean_price_unit']=result['mean_price_unit'].map(lambdax:round(x))

result['area']=result['area'].map(lambdax:str(x)+'區(qū)')

#繪制地圖

map=(

Map()

.add(

series_name='房源數(shù)量',

data_pair=[list(z)forzinzip(result['area'],result['count'])],

maptype='北京',

label_opts=opts.LabelOpts(is_show=True,font_size=10)

)

.add(

series_name='平均單價',

16

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

data_pair=list(zip(result['area'],result['mean_price_unit'])),

maptype='北京',

label_opts=opts.LabelOpts(is_show=False)

)

.set_global_opts(

title_opts=opts.TitleOpts(title='北京市房源分布'),

visualmap_opts=opts.VisualMapOpts(

max_=max(result['count']),

range_color=['#fff','#00BFFF','#00FA9A','#FFD700','#FF8C00','#FF0000'],

)))

#保存為HTML文件

map.render('beijing_map.html')

運行結(jié)果如下圖所示:

圖5-1北京市地圖

北京市的房價整體上呈現(xiàn)區(qū)域性分布,從平均價格單位來看,東城區(qū)、西

城區(qū)和海淀區(qū)屬于高房價區(qū),分別為114、129和102萬元/平方米,且這些區(qū)

域的二手房數(shù)量相對較少,說明這些區(qū)域的房價相對較高且供給較為緊張。北

京市的中等房價區(qū)主要分布在豐臺區(qū)、石景山區(qū)和昌平區(qū),二手房的平均價格

17

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

分別為61、54和48萬元/平方米,且這些區(qū)域的二手房數(shù)量相對較多,說明這

些區(qū)域的房價相對較為平穩(wěn),供求相對平衡。北京市的低房價區(qū)主要分布在大

興區(qū)、通州區(qū)和懷柔區(qū),二手房的平均價格分別為44、44和30元/平方米,且

這些區(qū)域的二手房數(shù)量相對較多,說明這些區(qū)域的房價相對較低且供給相對充

足。綜上所述,北京市的房價整體呈現(xiàn)出明顯的區(qū)域性分布,不同區(qū)域的房價

和二手房數(shù)量有著明顯的差異,投資者在購買房產(chǎn)時應該綜合考慮各方面因素,

以選擇適合自己的房產(chǎn)投資方案。

5.2.2統(tǒng)計不同朝向與樓層的房源數(shù)量與價格

使用了pandas和pyecharts庫來讀取一個JSON文件并繪制柱狀圖。首先,

代碼使用pandas的read_json()方法讀取一個名為house_clean.json的JSON

文件,其中l(wèi)ines=True參數(shù)表示每一行都是一個JSON對象。然后,代碼使用

str.strip()方法剔除了direction字段中的空格,并使用map()方法將

price_unit字段中的字符串類型轉(zhuǎn)換為浮點型,去掉了單位和千位分隔符。

接下來,代碼使用groupby()方法將數(shù)據(jù)按照floor_level字段進行分組,

然后使用agg()方法對每個組內(nèi)的數(shù)據(jù)進行統(tǒng)計,其中count表示數(shù)量,mean

表示平均值。最后,代碼使用reset_index()方法將分組后的數(shù)據(jù)重新設(shè)置索

引。接著,代碼使用pyecharts庫的Bar()類創(chuàng)建一個柱狀圖對象。使用

add_xaxis()方法添加x軸數(shù)據(jù),使用add_yaxis()方法添加y軸數(shù)據(jù),并使用

set_global_opts()方法設(shè)置全局參數(shù),例如標題和x軸名稱。

importpandasaspd

frompyecharts.chartsimportBar

frompyechartsimportoptionsasopts

#讀取json文件

df=pd.read_json('house_clean.json',lines=True)

#剔除direction中的空格

df['direction']=df['direction'].str.strip()

df['price_unit']=df['price_unit'].map(lambdax:float(str(x).replace('元','').replace(',','.')))

#根據(jù)floor_level分組,求數(shù)量和price_unit平均價格

grouped=df.groupby('floor_level').agg({'house_name':'count','price_unit':

'mean'}).reset_index()

grouped['price_unit']=grouped['price_unit'].map(lambdax:round(x))

18

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

#繪制柱狀圖

bar_chart=(

Bar()

.add_xaxis(list(grouped['floor_level']))

.add_yaxis("數(shù)量",list(grouped['house_name']))

.add_yaxis("平均價格",list(round(grouped['price_unit'],2)))

.set_global_opts(

title_opts=opts.TitleOpts(title="按樓層分組統(tǒng)計"),

xaxis_opts=opts.AxisOpts(name="樓層"),

))

bar_chart.render('柱狀圖.html')

圖5-2柱狀圖

從平均價格單位來看,地下室的二手房平均價格最高,為68萬元/平方米,

其次是低樓層和頂層,分別為66和57萬元/平方米,這可能是因為地下室的房

屋位置特殊,且擁有更好的采光條件;而低樓層和頂層則可能因為存在噪音、

采光、通風等方面的問題,導致其價格相對較低。從二手房數(shù)量來看,中樓層

的二手房數(shù)量最多,達到了6706套,其次是高樓層和低樓層,分別為3904和

3597套,這可能是因為中樓層的位置相對較為舒適,采光、通風等方面的條件

較好??傮w來說,不同樓層的二手房價格和數(shù)量都有一定的差異,投資者在購

買房產(chǎn)時應該綜合考慮各方面因素,以選擇適合自己的樓層投資方案。

19

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

5.2.3統(tǒng)計各裝修風格的數(shù)量

使用Pandas的read_json函數(shù)讀取一個名為"house_clean.json"的JSON

格式文件,并將其轉(zhuǎn)換為一個DataFrame對象df。對DataFrame中的

"price_unit"列進行數(shù)據(jù)清洗,將其中的"元"字符剔除并將逗號替換為小數(shù)點,

最終轉(zhuǎn)換為float類型。使用groupby函數(shù)對DataFrame對象df按照

"decoration"列進行分組,統(tǒng)計每組中"house_name"的數(shù)量,并計算每組中

"price_unit"的平均值。使用Pyecharts中的Pie()函數(shù)創(chuàng)建一個餅圖對象,

通過add方法將數(shù)據(jù)添加到餅圖中,設(shè)置全局選項和系列選項,最后使用render

方法將餅圖保存到名為"餅圖.html"的文件中。

importpandasaspd

frompyecharts.chartsimportPie

frompyechartsimportoptionsasopts

#讀取json文件

df=pd.read_json('house_clean.json',lines=True)

#剔除price_unit中的“元”字符并將逗號替換成.

df['price_unit']=df['price_unit'].str.replace('元','').str.replace(',','').astype(float)

#根據(jù)decoration分組,求數(shù)量和price_unit平均價格

grouped=df.groupby('decoration').agg({'house_name':'count'}).reset_index()

#繪制餅圖

pie_chart=(

Pie()

.add("數(shù)量",[list(z)forzinzip(grouped['decoration'],list(grouped['house_name']))])

.set_global_opts(

title_opts=opts.TitleOpts(title="按裝修程度分組統(tǒng)計",padding=10),

legend_opts=opts.LegendOpts(orient="vertical",

pos_left="left",padding=70,item_width=10,item_height=10)

).set_series_opts(label_opts=opts.LabelOpts(formatter=":{c}")))

pie_chart.render('餅圖.html')

20

湖南商務職業(yè)技術(shù)學院畢業(yè)設(shè)計

圖5-3餅圖

從數(shù)量來看,精裝二手房數(shù)量最多,達到了11505套,其次是簡裝和其他,

分別為8844和3200套,而毛坯二手房數(shù)量最少,為761套。在當前的房地產(chǎn)

市場,二手房市場上,精裝房屋的銷售較為受歡迎,可能是因為精裝房屋已經(jīng)

在內(nèi)部裝修和裝飾方面花費了大量的人力和物力,從而為購房者提供了更好的

住宿體驗。在購買二手房時,裝修風格也是一個非常重要的因素,購房者需要

根據(jù)自己的需求和喜好來選擇不同的裝修風格,以滿足自己的住宿需求。

5.2.4統(tǒng)計每年建造的房屋數(shù)量與價格

使用pyecharts庫,通過對讀取的數(shù)據(jù)進行一些處理和統(tǒng)計,繪制了一個

折線圖。具體地,代碼首先讀取了一個JSON文件house_clean.json,然后使

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論