緣起
第一次接觸“租售比”這個概念是在知乎?團支書?對?如何通過房屋租售比來判斷房產的價值或泡沫??這個問題的回答上看到的,當時看到她搞出來的一些圖和分析就感覺很有意思,尋思著自己也可以嘗試用相同的方法對北京的房屋租售信息做一個分析。沒想到一搜索,類似的東西早就有人做出來了。比如在知乎上的這個問題:北京在哪里租房的居住性價比高?。高票答案雖然來自鏈家旗下自如的員工,但是其以熱力圖一目了然的展示出了北京出租房房租的高低分布情況,難怪下面會有知友回復說:廣告滿分。然后還有這篇文章【租房數據分析】2016年在北京如何租到好房子?,再加上今年這剛一開始,北京、上海的房價又開始一輪瘋漲,自然就更讓大家開始關注房產有關的信息。于是,個人也嘗試著把這個事情搞一搞。
python gui?處理流程
首先來看處理流程,其實就是一個數據收集、處理、分析和展示的過程。
對于數據收集,58同城、趕集網、鏈家網這些上面有著豐富的信息,只不過對于前面兩個網站,現在,哦,可能一直都是這樣,已經差不多都被中介信息給淹沒了。所以即使這些網站已經提供了大量的信息,但是如果真的想拿來使用,還是要進行一些處理。
python編程?對于數據分析,相信每個人都有自己獨特的視角,同樣一份數據,不同的人有著不同的關注點,所以很難制定統一的規則,這里就單從價格這一方面來做一個統計。
對于數據展示,因為要看的是一個城市的數據,因此熱力圖是一個很好的選擇,而百度地圖已經提供了很方便的接口,所以這里使用百度的地圖接口來進行熱力圖的展示。
由此,處理流程大致分為一下幾個步驟:
python3,選定某個城市
抓取區域信息
制定翻頁規則
用python爬取網站數據。抓取租售信息
獲取位置信息
生成價格熱圖
詳細流程
這里以趕集網的二手房銷售信息為例,演示如何抓取數據并將結果展示到熱力圖上。
頁面分析
首先打開?趕集網北京站,可以看到,排在左上角的就是”北京房產”, 由這個位置就可以想見,房地產相關的業務得占了它全站多大的比例。
我們直接點擊?二手房?來看一下這個頁面,發現上面給出了北京市的幾個區域,方便用戶在特定城區查找房源。
如果你看過知乎上的這個問答:如何不吹牛地形容北京有多大?,那么你一定會理解對于帝都來說,只給出一個城區那范圍有點太大了。所幸,這些網站都在某個區域下給出了更詳細分區。
頁面的下半部分,是各大中介發布的出售信息,先別為令人咋舌的房價感慨,隨便點開一條信息,進入到詳細頁面,可以看到里面把總價、單價、戶型、樓層、小區、位置等都描述的非常清楚了,有點甚至連首付和月供都已經幫你算好了。這么豐富的信息,基本上已經滿足了從多個維度對房產信息進行分析統計。
但是作為演示,暫時沒有必要搞那么復雜,這里只需要統計一下每個小區的均價,給出按照小區價格的熱力圖就可以了。
在詳細頁面里給出了該條出售信息的房源所屬的小區,點擊進入小區的詳細頁面,可以看到小區有著這樣一個結構。
點擊上一級頁面,我們看到有關小區的列表頁,而且這里已經給出了某個小區的均價。
由此我們可以制定我們的抓取策略。首先我們抓取某個城市的區域信息,然后抓取某個區域下面的子區域信息,最后再抓取某個子區域下的小區信息。
這里還有一個問題需要注意,某個區域下的小區列表可能不僅僅只有一頁,所以還要處理翻頁。
由圖即可看到翻頁的規律。
數據抓取
這里使用最簡單的方式-基于?urllib2?進行頁面抓取
1
2
3
4
5
6
import urllib2
response = urllib2.urlopen('http://bj.ganji.com/xiaoqu')
html = response.read()
with open('index.html', 'w') as html_file:
html_file.write(html)
打開抓取的頁面,使用Chrome的開發者工具對HTML進行分析
由此即可根據?XPath?確定城市下面的區域選擇器為
1
area_select = '//dl[@class="selitem selitem-area lh24 clearfix"]//div[@class=" clearfix"]/a[@rel="nofollow"]'
以lxml作為解析HTML的工具,嘗試獲取城市的區域信息
1
2
3
4
5
6
7
8
from lxml import etree
html = file('index.html').read().decode('UTF-8')
doc = etree.HTML(html)
area_select = '//dl[@class="selitem selitem-area lh24 clearfix"]//div[@class=" clearfix"]/a[@rel="nofollow"]'
area_list = doc.xpath(area_select)
for area in area_list:
print area.xpath('string()'), area.get('href')
使用相同的方式,即可實現對某個區域下子區域信息的抓取,這里以海淀區為例
1
2
3
4
5
6
7
8
9
10
import urllib2
from lxml import etree
response = urllib2.urlopen('http://bj.ganji.com/xiaoqu/d0')
html = response.read()
doc = etree.HTML(html)
subarea_select = '//dl[@class="selitem selitem-area lh24 clearfix"]//div[@class="subarea clearfix"]/a[@rel="nofollow"]'
subarea_list = doc.xpath(subarea_select)
for subarea in subarea_list:
print subarea.xpath('string()'), subarea.get('href')
再來試試對某個子區域下小區信息的抓取,這里以宇宙中心-五道口為例
1
2
3
4
5
6
7
8
9
10
11
12
import urllib2
from lxml import etree
response = urllib2.urlopen('http://bj.ganji.com/xiaoqu/d0s11')
html = response.read()
doc = etree.HTML(html)
community_select = '//div[@class="listBox"]/ul/li]'
community_list = doc.xpath(community_select)
for community in community_list:
name = community.xpath('./div[@class="list-mod2"]/div[@class="info-title"]/a')[0].xpath('string()')
price = community.xpath('./div[@class="list-mod3 xq-price clearfix"]/p/b')[0].xpath('string()')
print name, price
數據展示
數據有了,接下來就是如何展示。
首先查看一下百度地圖的JavaScript API,里面提到
該套API免費對外開放。自v1.5版本起,您需先申請密鑰(ak)才可使用,接口(除發送短信功能外)無使用次數限制。
所以,注冊一個帳號,然后申請密鑰即可。
文檔里已經給出了一個熱力圖示例,通過源碼可以看到關鍵在于定義點坐標。
1
2
3
4
5
var points =[
{"lng":116.418261,"lat":39.921984,"count":50},
{"lng":116.423332,"lat":39.916532,"count":51},
{"lng":116.419787,"lat":39.930658,"count":15},
...]
Geocoding API 是一類簡單的HTTP接口,用于提供從地址到經緯度坐標或者從經緯度坐標到地址的轉換服務,用戶可以使用C# 、C++、Java等開發語言發送HTTP請求且接收JSON、XML的返回數據。
測試一下
1
2
3
4
5
6
7
8
import urllib2
ak = '密鑰'
city = '北京市'
address = '華清嘉園'
api_url = 'http://api.map.baidu.com/geocoder/v2/?ak=%s&output=json&city=%s&address=%s' % (ak, city, address)
result = urllib2.urlopen(api_url).read()
print result
返回結果格式如下
1
2
3
4
5
6
7
8
9
10
{"status": 0,
"result": {
"location": {
"lng": 116.34213332629,
"lat": 39.997261285991
},
"precise": 0,
"confidence": 60,
"level": "地產小區"
}}
有了它就可以批量完成已抓取小區的坐標轉換了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import urllib2
import json
def get_coordinate(address, ak='密鑰', city='北京市'):
api_url = 'http://api.map.baidu.com/geocoder/v2/?ak=%s&output=json&city=%s&address=%s' % (ak, city, address)
result = urllib2.urlopen(api_url).read()
return json.loads(result)
def transform(community_data):
points = []
for name, price in community_data.iteritems():
obj = get_coordinate(name)
if obj['status'] != 0:
continue
d = obj['result']['location']
d['price'] = float(price)
points.append(d)
with open('data/heatmap_data.js', 'w') as jsfile:
jsfile.write('var points = ' + json.dumps(points) + ';')
數據有了,現在只需要把熱力圖示例中給出的頁面修改一下,就可以顯示抓取到的結果了。
1
2
3
4
5
6
7
8
9
10
11
12
13
// var points = [
{"lng":116.418261,"lat":39.921984,"count":50},
{"lng":116.423332,"lat":39.916532,"count":51},
{"lng":116.419787,"lat":39.930658,"count":15},
...];
功能測試
根據趕集網的頁面規則,測試一下抓取效果
1
2
3
4
5
6
7
8
9
10
11
index_url = 'http://bj.ganji.com/xiaoqu'
create_new = False
city_model = CityModel(index_url=index_url, create_new=create_new)
page_select = '//div[@class="pageBox"]/ul/li/a'
community_select = '//div[@class="listBox"]/ul/li'
name_select = './div[@class="list-mod2"]/div[@class="info-title"]/a'
price_select = './div[@class="list-mod3 xq-price clearfix"]/p/b'
city_model.get_all_community(page_select, community_select, name_select, price_select)
city_model.save()
注意事項
既然是爬取別人網站上的數據,當然道德也很重要,我們來看一下趕集網Robots規則
1
2
3
4
5
6
7
8
9
10
11
User-agent: *
Disallow: /tel/*.png
Disallow: /*/?navtab=
Disallow: /404.html
Disallow: /findjob/send_resume.php
Disallow: /user/
Disallow: /misc/
Disallow: /zq_biyeji/
Disallow: /utils/
Disallow: /pub/
Disallow: /sorry/
還好我們只是抓取租售信息,這些都并不在屏蔽之列,只要不是抓的太狠(間隔時間過短),還是可以基于此嘗試做一些有趣的統計和分析的。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态