學習python抓取資料——鏈家北京二手房資料
最近在學習用Python進行資料分析、機器學習,基本都是用現成資料集進行模型訓練及驗證,想用一些實際資料看一下效果,於是想到用Python嘗試抓取一些實際資料。
目標:爬取鏈家網北京二手房房價、位置、面積等資料
環境:Python3.5.2,Anaconda4.2.0
1.準備工作
首先,匯入所需要的庫,主要有urllib.request、BeautifulSoup、Pandas、Numpy、re。
from urllib.request import urlopen
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import re
- urllib.request:開啟和瀏覽url中內容。具體用法參見:https://docs.python.org/3/library/urllib.request.html#module-urllib.request
- BeautifulSoup:將html解析為物件進行處理,全部頁面轉變為字典或者陣列,相對於正則表示式的方式,可以大大簡化處理過程。具體用法參見:https://www.crummy.com/software/BeautifulSoup/bs4/doc/
- Pandas: Pandas 是python的一個數據分析包,提供了大量能使我們快速便捷地處理資料的函式和方法。 具體用法參見:
- Numpy:Numpy支援高階大量的維度陣列與矩陣運算,針對陣列運算提供大量的數學函式庫。 具體用法參見:https://www.numpy.org/
- re:re是pyhton中實現正則表示式匹配操作的模組。具體用法參見:https://docs.python.org/3.5/library/re.html
2.抓取資料
首先,瞭解一下目標網站的URL結構,例如 https://bj.lianjia.com/ershoufang/dongcheng/pg2/
- bj表示城市,北京
- ershoufang是頻道名稱,二手房
- dongcheng是城區名稱,東城區
- pg2是頁面碼,第二頁
例如,我們要抓取北京各個區二手房頻道,所以前面城市、頻道名稱不會變,屬於固定部分;後面的城區要遍歷北京各個區(東城、西城、朝陽…),頁碼需要在1-所選城區總頁數間變化,屬於可變部分。將URL分為兩部分,前面的固定部分賦值給url,後面的可變部分用雙層for迴圈遍歷,外層迴圈遍歷城區,內層迴圈遍歷所選城區的頁面。其中,需要獲取所選城區包含的總頁數,提取div標籤中class=page-box fr的第一個子標籤屬性page-data的值。
chengqu={'dongcheng':'東城區','xicheng':'西城區','chaoyang':'朝陽區','haidian':'海淀區','fengtai':'豐臺區','shijingshan':'石景山區', 'tongzhou':'通州區','changping':'昌平區','daxing':'大興區','shunyi':'順義區','fangshan':'房山區'}
for cq in chengqu.keys():
url='https://bj.lianjia.com/ershoufang/'+cq+'/' #組成所選城區的URL
html=urlopen(url)
bsObj=BeautifulSoup(html) #解析抓取的頁面內容
total_page=re.sub('\D','',bsObj.find('div','page-box fr').contents[0].attrs['page-data'])[:-1] #獲取所選城區總頁數
print ('total_page',total_page)
for j in np.arange(1,int(total_page)+1):
page_url=url+'pg'+str(j) #組成所選城區頁面的URL
然後,使用BeautifulSoup對頁面進行解析。
page_html=urlopen(page_url)
page_bsObj=BeautifulSoup(page_html)
接著,提取頁面中的關鍵資訊進行提取,主要對房屋資訊、房屋位置、總價和單價進行提取。
依次把頁面div標籤中class為houseInfo、positionInfo、totalPrice、unitPrice的部分提取出來,用get_text()獲取對應標籤中的資訊,其中houseInfo、positionInfo包含房屋的多種屬性,用split()對其進行分列,只選取了houseInfo包含6個屬性且positionInfo包含3個屬性的資料。另外,對於單價用get_text()後得到“單價100748元/平米”,包含了文字和數字,用re.sub()正則匹配出數字部分。最後,依次把提取到的資訊新增到對應列表中。
info=bsObj.findAll("div",{"class":"houseInfo"})
position_info=bsObj.findAll("div",{"class":"positionInfo"})
totalprice=bsObj.findAll("div",{"class":"totalPrice"})
unitprice=bsObj.findAll("div",{"class":"unitPrice"})
house_loc=[] #房屋所在小區
house_type=[] #房屋戶型
house_area=[] #房屋面積
house_direction=[] #房屋朝向
house_decorating=[] #房屋裝修
house_lift=[] #有無電梯
house_floor=[] #房屋樓層
house_year=[] #建造年份
house_position=[] #房屋位置
t_price=[] #房屋總價
u_price=[] #房屋單價
for i_info,i_pinfo,i_tp,i_up in zip(info,position_info,totalprice,unitprice):
if len(i_info.get_text().split('/'))==6 and len(i_pinfo.get_text().split('/'))==3:
#分列houseinfo並依次獲取房屋所在小區、戶型、面積、朝向、裝修、有無電梯各欄位
house_loc.append(i_info.get_text().split('/')[0])
house_type.append(i_info.get_text().split('/')[1])
house_area.append(i_info.get_text().split('/')[2][:-2])
house_direction.append(i_info.get_text().split('/')[3].replace(' ',''))
house_decorating.append(i_info.get_text().split('/')[4])
house_lift.append(i_info.get_text().split('/')[5])
#分列positioninfo並依次獲房屋樓層、建造年份、位置各欄位
house_floor.append(i_pinfo.get_text().split('/')[0])
house_year.append(i_pinfo.get_text().split('/')[1][:5])
house_position.append(i_pinfo.get_text().split('/')[2])
#獲取房屋總價和單價
t_price.append(i_tp.span.string)
u_price.append(re.sub('\D','',i_up.get_text()))
將提取的資料匯入pandas之中生成資料表。
#將資料匯入pandas之中生成資料表
house_data=pd.DataFrame()
house_data[u'城區']=[chengqu[cq]]*len(house_loc)
house_data[u'小區名稱']=house_loc
house_data[u'房型']=house_type
house_data[u'面積']=house_area
house_data[u'朝向']=house_direction
house_data[u'裝修']=house_decorating
house_data[u'有無電梯']=house_lift
house_data[u'樓層']=house_floor
house_data[u'建造年份']=house_year
house_data[u'位置']=house_position
house_data[u'總價']=t_price
house_data[u'單價']=u_price
print (house_data)
將資料存入到csv中,便於後續分析。
house_data.to_csv('house_bj.csv', mode='a', header=False,ecoding='gb2312',index=None)
總共提取到北京11個區28560條二手房資訊。
最後,附上完整程式碼~~
from urllib.request import urlopen
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import re
chengqu={'dongcheng':'東城區','xicheng':'西城區','chaoyang':'朝陽區','haidian':'海淀區','fengtai':'豐臺區','shijingshan':'石景山區',
'tongzhou':'通州區','changping':'昌平區','daxing':'大興區','shunyi':'順義區','fangshan':'房山區'}
for cq in chengqu.keys():
url='https://bj.lianjia.com/ershoufang/'+cq+'/' #組成所選城區的URL
html=urlopen(url)
bsObj=BeautifulSoup(html)
total_page=re.sub('\D','',bsObj.find('div','page-box fr').contents[0].attrs['page-data'])[:-1] #獲取所選城區總頁數
print ('total_page',total_page)
for j in np.arange(1,int(total_page)+1):
page_url=url+'pg'+str(j) #組成所選城區頁面的URL
#print (page_url)
page_html=urlopen(page_url)
page_bsObj=BeautifulSoup(page_html)
info=bsObj.findAll("div",{"class":"houseInfo"})
position_info=bsObj.findAll("div",{"class":"positionInfo"})
totalprice=bsObj.findAll("div",{"class":"totalPrice"})
unitprice=bsObj.findAll("div",{"class":"unitPrice"})
house_loc=[] #房屋所在小區
house_type=[] #房屋戶型
house_area=[] #房屋面積
house_direction=[] #房屋朝向
house_decorating=[] #房屋裝修
house_lift=[] #有無電梯
house_floor=[] #房屋樓層
house_year=[] #建造年份
house_position=[] #房屋位置
t_price=[] #房屋總價
u_price=[] #房屋單價
for i_info,i_pinfo,i_tp,i_up in zip(info,position_info,totalprice,unitprice):
if len(i_info.get_text().split('/'))==6 and len(i_pinfo.get_text().split('/'))==3:
#分列houseinfo並依次獲取房屋所在小區、戶型、面積、朝向、裝修、有無電梯各欄位
house_loc.append(i_info.get_text().split('/')[0])
house_type.append(i_info.get_text().split('/')[1])
house_area.append(i_info.get_text().split('/')[2][:-2])
house_direction.append(i_info.get_text().split('/')[3].replace(' ',''))
house_decorating.append(i_info.get_text().split('/')[4])
house_lift.append(i_info.get_text().split('/')[5])
#分列positioninfo並依次獲房屋樓層、建造年份、位置各欄位
house_floor.append(i_pinfo.get_text().split('/')[0])
house_year.append(i_pinfo.get_text().split('/')[1][:5])
house_position.append(i_pinfo.get_text().split('/')[2])
#獲取房屋總價和單價
t_price.append(i_tp.span.string)
u_price.append(re.sub('\D','',i_up.get_text()))
#將資料匯入pandas之中生成資料表
house_data=pd.DataFrame()
house_data[u'城區']=[chengqu[cq]]*len(house_loc)
house_data[u'小區名稱']=house_loc
house_data[u'房型']=house_type
house_data[u'面積']=house_area
house_data[u'朝向']=house_direction
house_data[u'裝修']=house_decorating
house_data[u'有無電梯']=house_lift
house_data[u'樓層']=house_floor
house_data[u'建造年份']=house_year
house_data[u'位置']=house_position
house_data[u'總價']=t_price
house_data[u'單價']=u_price
#print (house_data)
#將資料存入到csv中,便於後續分析
house_data.to_csv('house_bj.csv', mode='a', header=False,ecoding='gb2312',index=None)