使用python抓取并分析數據—鏈家網(requests+BeautifulSoup)

azkb6080 8年前發布 | 27K 次閱讀 Python開發 beautifulsoup

本篇文章是使用python抓取數據的第一篇,使用request+BeautifulSoup的方法對頁面進行抓取和數據提取。通過使用requests庫對鏈家網二手房列表頁進行抓取,通過BeautifulSoup對頁面進行解析,并從中獲取房源價格,面積,戶型和關注度的數據。

準備工作

首先是開始抓取前準備工作,導入需要使用的庫文件,這里主要使用的是requests和BeautifulSoup兩個。Time庫負責設置每次抓取的休息時間。這里并非全部,后續還會在過程中導入新的庫。

import requests
import time
from bs4 import BeautifulSoup

抓取列表頁

開始抓取前先觀察下目標頁面或網站的結構,其中比較重要的是URL的結構。鏈家網的二手房列表頁面共有100個,URL結構為http://bj.lianjia.com/ershoufang/pg9/,其中bj表示城市,/ershoufang/是頻道名稱,pg9是頁面碼。我們要抓取的是北京的二手房頻道,所以前面的部分不會變,屬于固定部分,后面的頁面碼需要在1-100間變化,屬于可變部分。將URL分為兩部分,前面的固定部分賦值給url,后面的可變部分使用for循環。

#設置列表頁URL的固定部分
url='http://bj.lianjia.com/ershoufang/'
#設置頁面頁的可變部分
page=('pg')

此外,還需要在很http請求中設置一個頭部信息,否則很容易被封。頭部信息網上有很多現成的,也可以使用httpwatch等工具來查看。具體細節按照具體情況進行調整。

#設置請求頭部信息
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
'Accept':'text/html;q=0.9,*/*;q=0.8',
'Accept-Charset':'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'Accept-Encoding':'gzip',
'Connection':'close',
'Referer':'http://www.baidu.com/link?url=_andhfsjjjKRgEWkj7i9cFmYYGsisrnm2A-TN3XZDQXxvGsM9k9ZZSnikW2Yds4s&wd=&eqid=c3435a7d00006bd600000003582bfd1f'
}

使用for循環生成1-100的數字,轉化格式后與前面的URL固定部分拼成要抓取的URL。這里我們設置每兩個頁面間隔0.5秒。抓取到的頁面保存在html中。

#循環抓取列表頁信息
for i in range(1,100):
     if i == 1:
          i=str(i)
          a=(url+page+i+'/')
          r=requests.get(url=a,headers=headers)
          html=r.content
     else:
          i=str(i)
          a=(url+page+i+'/')
          r=requests.get(url=a,headers=headers)
          html2=r.content
          html = html + html2
     #每次間隔0.5秒
     time.sleep(0.5)

解析頁面并提取信息

頁面抓取完成后無法直接閱讀和進行數據提取,還需要進行頁面解析。我們使用BeautifulSoup對頁面進行解析。變成我們在瀏覽器查看源代碼中看到的樣子。

#解析抓取的頁面內容
lj=BeautifulSoup(html,'html.parser')

完成頁面解析后就可以對頁面中的關鍵信息進行提取了。下面我們分別對房源的總價,房源信息和關注度三部分進行提取。

把頁面div標簽中class=priceInfo的部分提取出來,并使用for循環將其中每個房源的總價數據存在tp中。

#提取房源總價
price=lj.find_all('div',attrs={'class':'priceInfo'})
tp=[]
for a in price:
    totalPrice=a.span.string
    tp.append(totalPrice)

提取房源信息和關注度的方法與提取房源價格的方法類似,下面是具體的代碼,房源信息存儲在hi中,關注度存儲在fi中。

#提取房源信息
houseInfo=lj.find_all('div',attrs={'class':'houseInfo'})

hi=[]
for b in houseInfo:
    house=b.get_text()
    hi.append(house)
#提取房源關注度
followInfo=lj.find_all('div',attrs={'class':'followInfo'})

fi=[]
for c in followInfo:
    follow=c.get_text()
    fi.append(follow)

創建數據表并清洗數據

導入pandas庫將前面提取的房源總價,和關注度等信息進行匯總生成數據表。便于后面的分析。

#導入pandas庫
import pandas as pd
#創建數據表
house=pd.DataFrame({'totalprice':tp,'houseinfo':hi,'followinfo':fi})
#查看數據表的內容
house.head()

前面提取的都只是信息,還不能直接使用,在分析前要對這些信息進行數據提取和清洗等工作。如房源信息,在表中每個房源的小區名稱,戶型,面積,朝向等信息都在一個字段中,無法直接使用。需要先進行分列操作。這里的規則比較明顯,每個信息間都是以豎線分割的,因此我們只需要以豎線進行分列即可。

#對房源信息進行分列
houseinfo_split = pd.DataFrame((x.split('|') for x in house.houseinfo),index=house.index,columns=['xiaoqu','huxing','mianji','chaoxiang','zhuangxiu','dianti'])

這是完成分列后的新數據表,房源的各種信息以及成為單獨的字段。

#查看分列結果
houseinfo_split.head()

將分列后的新數據表在重新拼接回原有的數據表中,這樣在后面的分析過程中可以與其他字段的信息配合使用。

#將分列結果拼接回原數據表
house=pd.merge(house,houseinfo_split,right_index=True, left_index=True)

完成拼接后的數據表中既包含了原有字段,也包含了分列后的新增字段。

#查看拼接后的數據表
house.head()

使用相同的方法對房源關注度字段進行分列和拼接操作。這里的分列規則是斜杠。

#對房源關注度進行分列
followinfo_split = pd.DataFrame((x.split('/') for x in house.followinfo),index=house.index,columns=['guanzhu','daikan','fabu'])
#將分列后的關注度信息拼接回原數據表
house=pd.merge(house,followinfo_split,right_index=True, left_index=True)

房源戶型分布情況

前面我們經過對房源信息的分列獲取了房源的朝向,戶型等信息,這里我們對房源的戶型情況進行匯總,看看北京在售二手房的戶型分布情況。

首先按房源的戶型對房源數量進行匯總,下面是具體的代碼和結果。

#按房源戶型類別進行匯總
huxing=house.groupby('huxing')['huxing'].agg(len)
#查看戶型匯總結果
huxing

導入數值計算庫mumpy對數據進行處理,并使用matplotlib繪制房源戶型分布條形圖。

#導入圖表庫
import matplotlib.pyplot as plt
#導入數值計算庫
import numpy as np
#繪制房源戶型分布條形圖
plt.rc('font', family='STXihei', size=11)
a=np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])
plt.barh([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],huxing,color='#052B6C',alpha=0.8,align='center',edgecolor='white')
plt.ylabel('戶型')
plt.xlabel('數量')
plt.xlim(0,1300)
plt.ylim(0,20)
plt.title('房源戶型分布情況')
plt.legend(['數量'], loc='upper right')
plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4)
plt.yticks(a,('1室0廳','1室1廳','1室2廳','2室0廳','2室1廳','2室2廳','3室0廳','3室1廳','3室2廳','3室3廳','4室1廳','4室2廳','4室3廳','5室2廳','5室3廳','6室1廳','6室2廳','7室2廳','7室3廳'))
plt.show()

北京在售二手房中戶型從1室0廳到7室3廳近20種分布廣泛。在所有的戶型中數量最多的是2室1廳,其次為3室1廳和3室2廳,以及2室2廳。較小的1室1廳數量也較多。較大的戶型數量較少。另外,從在售戶型的分布中我們也可以推測出售房人的一些情況。

 

房源面積分布情況

在數據表中,房源面積通過分列以及單獨提取出來,但數字與中文的格式并不能直接使用。我們還需要對房源面積字段進行二次分列處理,提取出面積的數值。方法與前面的分列方法類似,我們使用“平”作為分列規則對房源面積進行二次分列。并將分列后的結果拼接回原數據表中。

#對房源面積進行二次分列
mianji_num_split = pd.DataFrame((x.split('平') for x in house.mianji),index=house.index,columns=['mianji_num','mi'])
#將分列后的房源面積拼接回原數據表
house=pd.merge(house,mianji_num_split,right_index=True, left_index=True)

分列后的數據在使用前還需要進行清洗,通常的操作包括去除空格和格式轉換。下面我們先對房源面積的值去除兩端的空格,然后更改數值的格式以方便后面的計算。

#去除mianji_num字段兩端的空格
house['mianji_num']=house['mianji_num'].map(str.strip)
#更改mianji_num字段格式為float
house['mianji_num']=house['mianji_num'].astype(float)

清洗后的房源面積字段可以開始分析了。首先查看所有北京在售二手房的面積范圍,下面是代碼和結果。房源面積從18.85到332.63。

#查看所有房源面積的范圍值
house['mianji_num'].min(),house['mianji_num'].max()
(18.850000000000001, 332.63)

有了房源面積的范圍后,就可以對面積進行分組了,我們以50為區間將房源面積分為7組。并統計所有房源在這7組中的分布情況。

#對房源面積進行分組
bins = [0, 50, 100, 150, 200, 250, 300, 350]
group_mianji = ['小于50', '50-100', '100-150', '150-200','200-250','250-300','300-350']
house['group_mianji'] = pd.cut(house['mianji_num'], bins, labels=group_mianji)
#按房源面積分組對房源數量進行匯總
group_mianji=house.groupby('group_mianji')['group_mianji'].agg(len)

使用房源面積分組字段對房源數量進行分組并繪制條形圖。

#繪制房源面積分布圖
plt.rc('font', family='STXihei', size=15)
a=np.array([1,2,3,4,5,6,7])
plt.barh([1,2,3,4,5,6,7],group_mianji,color='#052B6C',alpha=0.8,align='center',edgecolor='white')
plt.ylabel('面積分組')
plt.xlabel('數量')
plt.title('房源面積分布')
plt.legend(['數量'], loc='upper right')
plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4)
plt.yticks(a,('小于50', '50-100', '100-150', '150-200','200-250','250-300','300-350'))
plt.show()

在所有房源中,數量最多的是50-100,其次為100-150。隨著面積增加數量減少。小于50的小面積房源也有一定數量的房源。

 

房源關注度分布情況

房源關注度的情況與房源面積類似,第一次分列處理后得到的數據包含數字和中文,無法直接使用,需要再次通過分列處理提取關注度的數值,并對數值進行清洗和格式轉換。下面是具體的代碼。

#對房源關注度進行二次分列
guanzhu_num_split = pd.DataFrame((x.split('人') for x in house.guanzhu),index=house.index,columns=['guanzhu_num','ren'])
#將分列后的關注度數據拼接回原數據表
house=pd.merge(house,guanzhu_num_split,right_index=True, left_index=True)
#去除房源關注度字段兩端的空格
house['guanzhu_num']=house['guanzhu_num'].map(str.strip)
#更改房源關注度及總價字段的格式
house[['guanzhu_num','totalprice']]=house[['guanzhu_num','totalprice']].astype(float)

清洗完后查看所有房源關注度的區間,關注度從0到725。也就是說有些房子很熱門,而有些房子沒有人關注。這可能和房源上線和更新的情況有關,此外還要考慮房源的銷售速度,熱門房源可能很搶手,剛上線就成交了。因此我們對情況進行簡化,暫時忽略掉這些復雜的情況。僅對關注度的分布情況進行統計。

#查看房源關注度的區間
house['guanzhu_num'].min(),house['guanzhu_num'].max()
(0.0, 725.0)

將關注度以100為區間分為8組,并按關注度區間進行匯總統計房源數量。查看在售房源的關注度分布情況。

#對房源關注度進行分組
bins = [0, 100, 200, 300, 400, 500, 600, 700,800]
group_guanzhu = ['小于100', '100-200', '200-300', '300-400','400-500','500-600','600-700','700-800']
house['group_guanzhu'] = pd.cut(house['guanzhu_num'], bins, labels=group_guanzhu)
group_guanzhu=house.groupby('group_guanzhu')['group_guanzhu'].agg(len)

繪制房源關注度分布條形圖。

#繪制房源關注度分布圖
plt.rc('font', family='STXihei', size=15)
a=np.array([1,2,3,4,5,6,7,8])
plt.barh([1,2,3,4,5,6,7,8],group_guanzhu,color='#052B6C',alpha=0.8,align='center',edgecolor='white')
plt.ylabel('關注度分組')
plt.xlabel('數量')
plt.xlim(0,3000)
plt.title('房源關注度分布')
plt.legend(['數量'], loc='upper right')
plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4)
plt.yticks(a,('小于100', '100-200', '200-300', '300-400','400-500','500-600','600-700','700-800'))
plt.show()

在3000個房源中,近2500個房源的關注度小于100,關注度大于400的房源則較少。這里需要再次說明的是關注度數據無法準確的表示房源的熱門程度。熱門房源可能由于出售速度快而關注度較少。因此關注度數據僅供參考。

房源聚類分析

最后,我們對所有在售房源按總價,面積和關注度進行聚類分析。將在售房源按總價,面積和關注度的相似性分在不同的類別中。

#導入sklearn中的KMeans進行聚類分析
from sklearn.cluster import KMeans
#使用房源總價,面積和關注度三個字段進行聚類
house_type = np.array(house[['totalprice','mianji_num','guanzhu_num']])
#設置質心數量為3
clf=KMeans(n_clusters=3)
#計算聚類結果
clf=clf.fit(house_type)

通過計算我們將在售房源分為三個類別,下面是每個類別的中心點坐標。

#查看分類結果的中心坐標
clf.cluster_centers_
array([[ 772.97477064, 112.02389908, 58.96330275],
[ 434.51073861, 84.92950236, 61.20115244],
[ 1473.26719577, 170.65402116, 43.32275132]])
#在原數據表中標注所屬類別
house['label']= clf.labels_

根據三個類別在總價,面積和關注度三個點的中心坐標,我們將在售房源分為三個類別,第一個類別是總價低,面積低,關注度高的房源。第二個類別是總價居中,面積居中,關注度居中的類別。第三個類別是總價高,面積高,關注度低的類別。

從營銷和用戶體驗的角度來看,在廣告和列表頁的默認排序中應該給予總價400萬,面積80屬性的房源更高的權重。這個類別的房源可以吸引最多的用戶關注。

—【所有文章及圖片版權歸 藍鯨(王彥平)所有。歡迎轉載,但請注明轉自“藍鯨網站分析博客”。】—

 

來自:http://bluewhale.cc/2016-12-04/use-python-crawl-and-analysis-data-lianjia-requests-and-beautifulsoup.html

 

 本文由用戶 azkb6080 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!