1. 程式人生 > >房東要給我漲800房租,生氣的我用Python抓取帝都幾萬套房源信息,我主動漲了1000。

房東要給我漲800房租,生氣的我用Python抓取帝都幾萬套房源信息,我主動漲了1000。

__init__ tar extend 簡單 not in 詳細 分布 obj soho

老貓我在南五環租了一個80平兩居室,租房合同馬上到期,房東打電話問續租的事,想要加房租;我想現在國家正在也在抑制房價,房子價格沒怎麽漲,房租應該也不會漲,於是霸氣拒絕了,以下是聊天記錄:
技術分享圖片
確認不續租之後,兩三年沒找過房的我上網搜索租房,沒想到出來一坨自如,蛋殼,貝殼等中介網站;進去看看,各種房照非常漂亮,但是一看房租,想送給自己一首《涼涼》;附近房租居然比我當前房租高1000多RMB;自我安慰下,這些網站房源價格不是真實的,於是切換到我愛我家,鏈家等大中介平臺,結果發現房租價格都差不多;心想這才幾年,如果兩年前對自己狠點買了房,房租都夠還房貸了。為了生存,不甘心的我,決定把這些大網站的房源信息抓取下來進行分析,帝都這麽大總有一套適合自己。

說幹就幹,先找到市場上主要的中介平臺,主要關註我愛我家、鏈家、貝殼,還有類似於自如,蛋殼等長租公寓;還有一個問題,好像鏈家、貝殼、自如是一個大老板,鏈家房源和自如的都是混到一起的,整的我一個頭大;貝殼類似於京東,不僅自己自營,還允許其他平臺來入住這個平臺,這老板頭腦真是好使,折騰半天數據都在自己手裏了,總感覺房價與房租上漲感覺和這個貨有種說不清的關系。

最後決定使用Python抓取鏈家,我愛我家,與貝殼網租房信息。

租住小區門口就有一個鏈家,先從鏈家下手;抓取與分析過程如下:

1:查看鏈家租房信息,決定抓取那些數據;
2:請求行為分析;
3:分析使用知識點,
4:抓取實現;
5:對出租房源信息進行分析;

1.使用瀏覽器查看要抓取信息:

借助瀏覽器打開鏈家主頁,查看要抓取信息,如下圖:
技術分享圖片
從當前信息中可以看到,鏈家有近19000套再租房源(某些為單間);
抓取信息包括:所屬小區,戶型,面積,價格,所屬區域,具體地址,房齡,房屋編號及詳情頁地址;確認抓取信息後,分析請求行為,如何進行抓取。

2.請求行為分析:

使用瀏覽器打開頁面,查看請求過程,需要分下面幾步進行抓取:

1> 請求首頁:https://bj.lianjia.com/zufang/;
2>解析北京下行政區對對應url,註意,這裏不包括燕郊與香河;
3>按照行政區進行查找,提取頁面房源信息,並請求下一頁,直到請求結束;

整個請求過程如下:

技術分享圖片
確認抓取過程後,我們確認使用哪些知識點。

3.知識點分析:

整個抓取過程分為請求數據,提取信息,數據保存,老貓這邊使用Python實現,主要知識點如下:

1>請求數據:requests模塊;
2>提取信息:BeautifulSoup模塊;
3>數據保存:csv格式存儲,csv模塊;

請求行為與知識點分析完成後,老貓在Jupyter下完成了單頁數據抓取與提取,具體過程這裏不詳細講解了,直接上最終代碼與結果。

4.鏈家出租房信息抓取實現:

老貓在這裏使用類實現抓取,簡單描述實現過程:

1>整理思路,確認要做的事情,分步實現;
1>根據請求與提取行為定義類與相關方法;
2>將Jupyter下實現填充到對應方法中;
3>存儲類實現;
4>代碼調試與運行;

最終代碼如下:

#coding=utf-8
#Author: qimao

import requests
from bs4 import BeautifulSoup
import json
import csv
import time

class CsvSaveModule(object):
    #存儲csv類
    def __init__(self, fname = "info.csv"):
        self.f = open(fname, ‘w‘)
        self.fcsv = csv.writer(self.f)
        self.head = True

    def write(self, keys, data):
        #寫入字段
        if self.head:
            self.head = False
            self.fcsv.writerow(keys)
        #獲取並寫入數據
        values = [data.get(key, "") for key in keys]
        self.fcsv.writerow(values)

    def close(self):
        self.f.close()

class SpiderMoujia(object):
    def __init__(self, *args):
        ‘args:保存數據對象‘
        self.urlhead = ‘https://bj.lianjia.com/‘
        self.hds = args

    def reqPage(self, url):
        num = 0
        #一個頁面最多嘗試請求三次
        while num < 3:
            #請求頁面信息,添加請求異常處理,防止某個頁面請求失敗導致整個抓取結束,
            try:
                if url:
                    req = requests.get(url)
                    if req.status_code == 200:
                        #返回BeautifulSoup對象
                        return BeautifulSoup(req.text, ‘html5lib‘)
            except:
                pass
            time.sleep(3)
            num += 1

    def startCrawler(self, url):
        #抓取對外接口,Url為種子url
        self.startRequest(url)
        self.close()

    def startRequest(self, url):
        #開始抓取
        obj = self.reqPage(url)
        areas = obj.find(‘div‘, class_="option-list")
        #提取區域信息:海澱,朝陽,....
        listarea = areas.select(‘a[href^="/zufang/"]‘)
        for area in listarea[1:]:
            aurl = self.urlhead + area.get(‘href‘)
            district = area.text.strip()
            #按照區域進行抓取
            self.crawlerArea(aurl,district)

    def crawlerArea(self, url, district):
        #print(‘crawlerArea‘, url)
        page = self.reqPage(url)
        if not page:
            return
        #解析頁面信息
        self.parsePage(page,district)
        #獲取下一頁地址
        nextpage = self.getNextPage(page)
        if nextpage:
            urlhead = url.rsplit(‘/‘,1)[0]
            nexturl = ‘/‘.join([urlhead, nextpage])
            #繼續請求下一頁
            self.crawlerArea(nexturl,district)

    def extractInfo(self, node, css):
        snode = node.select_one(css)
        val = ‘‘
        if snode and snode.text:
            val = snode.text.strip()
        return val

    def parsePage(self, page,district):
        #主要功能,提取頁面信息
        listhouse = page.select(‘#house-lst > li‘)
        #定義出提取字段
        keys = [‘信息‘, ‘小區‘, ‘戶型‘, ‘價格‘, ‘面積‘, ‘區域‘,
                ‘位置‘, ‘樓層‘, ‘年份‘, ‘附加信息‘, ‘房屋ID‘, ‘詳情頁地址‘]
        for house in listhouse:
            hinfo = []
            #提取title, 小區,戶型,價格,面積
            cssexpress = [‘h2 a‘, ‘.where a‘, ‘.zone‘, ‘.num‘,‘.meters‘]
            info = house.select_one(".info-panel")
            if not info:
                continue
            for express in cssexpress:
                hinfo.append(self.extractInfo(info, express))
            #添加區域
            hinfo.append(district)
            #區域,樓層,年代
            hinfo.extend(info.select_one(‘.con‘).text.split(‘/‘))
            #房子其他信息,例如:地鐵,陽臺,供暖等
            spans = info.select_one(‘.view-label‘)
            hpoint = ‘,‘.join((spans.stripped_strings))
            hinfo.append(hpoint)
            #房子ID號,唯一標識
            hinfo.append(house.get(‘data-id‘))
            #房租詳情頁url
            hinfo.append(info.select_one(‘h2 a‘).get(‘href‘))

            #轉換成字典
            housedata = dict(zip(keys, hinfo))
            print (housedata)
            self.saveData(housedata)

    def getNextPage(self, page):
        try:
            #獲取下一頁
            pagenode = page.select_one(‘.page-box‘)
            pageinfo = pagenode.get(‘page-data‘)
            jdata = json.loads(pageinfo)
            curpage = jdata.get(‘curPage‘)
            total = jdata.get(‘totalPage‘)
            if (curpage < total):
                return ‘pg%d‘%(int(curpage+1))
        except:
            print(‘error‘)
            pass

    def saveData(self, data):
        #按照順序保存數據
        keys = [‘信息‘, ‘小區‘, ‘戶型‘, ‘價格‘, ‘面積‘, ‘區域‘,
                ‘位置‘, ‘樓層‘, ‘年份‘, ‘附加信息‘, ‘房屋ID‘, ‘詳情頁地址‘]
        [hd.write(keys, data) for hd in self.hds]

    def close(self):
        #列表解析關閉存儲模塊
        [hd.close() for hd in self.hds]

if __name__ == ‘__main__‘:
    #開始抓取
    url = ‘https://bj.lianjia.com/zufang/‘
    csvhd = CsvSaveModule(‘ljinfo.csv‘)
    spider = SpiderMoujia(csvhd)
    spider.startCrawler(url)

運行過程如下圖:
技術分享圖片
最終獲取了1W多套出租房信息;到這裏我完成鏈家出租房員信息抓取。

5.我愛我家與貝殼抓取分析。

我愛我家是一個老牌的房地產中介,老貓來帝都10年了,畢業當年大部分同學幹了當年認為比較正統的工作,一個另類同學去了我愛我家做中介,早些年他經常群裏發消息,給我們介紹房源,大家認為他是推銷,很少有人理他;最近同學聚會見面我問他:你當年為什麽不在使勁逼著我買房?同學擡起頭,吸了一口煙吐了一圈,說了一句話,讓我感覺夏天頓時涼爽了許多:‘逼你你也買不起,逼你你也買不起,逼你你也買不起,重要事情說三遍‘,感覺友誼的小船就要翻了。
下面我們來看我愛我家出租房源頁面信息,如下圖:
技術分享圖片
從頁面中我們可以看到,我愛我家有3.2萬套出租房源,房源信息比較直觀;通過分析發現抓取我愛我家請求行為與抓取鏈家類似,不同之處在於提取數據與提取過程;我們可以在基於鏈家爬蟲進行修改實現;具體實現過程在這裏不詳細講解,直接上抓取部分結果:

區域,地址,小區,價格,面積,樓層,裝修,地鐵附近,戶型,朝向,信息,附加信息,詳情
朝陽,望京,寶星國際,8000,64  平米,低樓層/25層,精裝,距離地鐵望京東450米,1  室  1  廳,南,寶星國際緊鄰望京SOHO 阿裏巴巴  精裝朝南大開間,"近地鐵,隨時看,拎包入住,押金減免",/zufang/41330436.html
朝陽,望京,炫彩嘉軒,6500,60  平米,中樓層/21層,精裝,距離地鐵望京東760米,1  室  0  廳,南,炫彩一居室老業主委托 我有鑰匙 鄰望京SOHO,"近地鐵,可短租,拎包入住,集中供暖",/zufang/41348206.html
朝陽,望京,寶星國際,8500,64  平米,高樓層/25層,精裝,距離地鐵望京東450米,1  室  1  廳,南北,望京SOHO旁寶星國際,鄰阿裏巴巴,綠地,南向大開間,"近地鐵,隨時看,拎包入住,押金減免",/zufang/41331126.html
朝陽,CBD,陽光100國際公寓,9500,48  平米,低樓層/33層,精裝,距離地鐵大望路391米,1  室  1  廳,北,陽光100國際公寓精裝開 二次裝修有鑰匙看房方便,"近地鐵,隨時看,免傭,拎包入住",/zufang/41330729.html
朝陽,望京,朝庭公寓,13000,112  平米,高樓層/27層,精裝,距離地鐵望京南476米,2  室  1  廳,南北,望京南朝庭公寓,鄰悠樂匯和方恒國際,看房有鑰匙,隨時看房,"近地鐵,隨時看,免傭,拎包入住",/zufang/41337320.html
朝陽,石佛營,日月東華,6700,66.3  平米,頂層/21層,精裝,距離地鐵十裏堡1072米,1  室  1  廳,南,石佛營新上婚房一居拎包入住 看房預約,"近地鐵,拎包入住,集中供暖",/zufang/41348814.html
朝陽,惠新西街,勝古北裏,2800,58  平米,底層/5層,精裝,距離地鐵惠新西街南口232米,3  室  1  廳,北,隨時看 隨時住三家合住正規中臥室精裝修,"近地鐵,隨時看,拎包入住,集中供暖",/zufang/41338276.html
朝陽,潘家園,弘善家園,5300,61  平米,中樓層/13層,精裝,距離地鐵十裏河691米,1  室  1  廳,南,十裏河 潘家園10號線 弘善家園精裝正規一居 拎包入住,"近地鐵,拎包入住",/zufang/41334177.html
朝陽,東壩,朝陽新城一區,6500,114  平米,中樓層/6層,精裝,,2  室  1  廳,南北,朝陽新城一區兩室一廳,隨時看,/zufang/41351101.html
朝陽,十裏堡,十裏堡,6000,60  平米,底層/4層,中裝,距離地鐵十裏堡781米,2  室  1  廳,南北,6號線 十裏堡 南北兩居帶小院子 居家必備,"近地鐵,隨時看,集中供暖",/zufang/41345370.html
朝陽,十裏堡,十裏堡北裏,5000,50  平米,中樓層/13層,中裝,距離地鐵十裏堡371米,1  室  1  廳,南北,十裏堡 八裏莊北裏 晨光家園  隨時看,"近地鐵,免傭",/zufang/41342158.html
朝陽,南沙灘,南沙灘小區,7000,65  平米,中樓層/6層,精裝,距離地鐵北沙灘775米,2  室  1  廳,南北,南沙灘 中間層兩居室 臨地鐵北辰中科院 有鑰匙,"近地鐵,隨時看,拎包入住",/zufang/41341943.html
朝陽,管莊,管莊周井大院,6000,72  平米,中樓層/5層,精裝,距離地鐵雙橋604米,3  室  1  廳,南北,管莊周井大院精裝三居室出租 隨時入住,"近地鐵,隨時看,拎包入住,集中供暖",/zufang/41339579.html
朝陽,百子灣,金泰先鋒,10000,92  平米,底層/11層,精裝,距離地鐵百子灣437米,2  室  1  廳,南北,金泰先鋒 南北兩室一廳一廚一衛,"近地鐵,拎包入住,集中供暖",/zufang/41328442.html
朝陽,北苑,蘊實園,5800,66.37  平米,中樓層/14層,精裝,距離地鐵北苑571米,1  室  1  廳,南,鑰匙房源,看房隨時。,"近地鐵,隨時看,拎包入住",/zufang/41349514.html
朝陽,芍藥居,芍藥居,13000,118.38  平米,中樓層/14層,簡裝,距離地鐵芍藥居116米,3  室  1  廳,南,芍藥居南裏精裝修三室一廳,"近地鐵,隨時看,拎包入住,集中供暖",/zufang/41348855.html
朝陽,雙橋,東一時區,4500,65  平米,中樓層/26層,精裝,距離地鐵管莊1214米,1  室  1  廳,西北,管莊 東一時區 精裝一居室 家電齊全 隨時入住看房,"近地鐵,拎包入住,集中供暖",/zufang/41346286.html
...

最後我們來看貝殼抓取,貝殼是近些年起來的中介平臺,有點類京東,不僅有鏈家,自如房源,還有其他家;除了貝殼,還有其他很多短租長租平臺,例如小豬短租,蛋殼等;
有時候我常思考一個問題:

負能量:這些網站都是IT開發人員搞得,我們都是一個行業,為什麽要自己坑自己。如果沒有這麽多中介平臺去搶房源,炒房價,價格可能落下來;
正能量:中介傷根據市場需求搭建中介平臺,使廣大租客可以從正規渠道租房,遠離黑中介,給我們省去很多租房過程中遇到難題與煩惱,我們應該感謝這些中介商。
下面我們看下貝殼網頁面信息:
技術分享圖片
貝殼房源信息中除了基本信息,還包括房源屬於誰,例如:自如,鏈家,xx公寓等;貝殼抓取過程和鏈家也是類似的,具體實現在這裏不詳細講解,直接看我們抓取的數據:


中介商,價格,面積,信息,區域,位置,戶型,樓層,附加信息,詳情頁地址
鏈家,14000,84㎡,整租 · 海運倉小區 3室1廳 14000元,東城,東直門,3室1廳1衛,低樓層(7層),"近地鐵,精裝,集中供暖",/zufang/BJ2058598225715675136.html
鏈家,9200,89㎡,整租 · 安定門 安德路 精裝修大兩居 可拎包入住,東城,安定門,2室1廳1衛,高樓層(19層),"近地鐵,精裝",/zufang/BJ2047499309347512320.html
鏈家,6000,61㎡,整租 · 安化南裏 1室1廳 6000元,東城,廣渠門,1室1廳1衛,低樓層(16層),"近地鐵,新上,隨時看房",/zufang/BJ2062732570394894336.html
鏈家,3500,14㎡,整租 · 南剪子巷 1室1廳 3500元,東城,東四,1室1廳0衛,低樓層(1層),"近地鐵,新上,隨時看房",/zufang/BJ2064894449783685120.html
鏈家,25000,158㎡,整租 · 東城逸墅南北通透大三居 婚房出租 可看房 家具齊全,東城,工體,3室1廳2衛,中樓層(7層),"近地鐵,精裝,集中供暖,雙衛生間,隨時看房",/zufang/BJ2034641117466591232.html
城家精選公寓,11300,43㎡,整租 · 元嘉國際公寓 1室0廳,東城,東直門,1室0廳1衛,未知(10層),"公寓,租房節,七天換租,近地鐵,精裝,集中供暖,免中介費,押一付一,新上",/zufang/BJ2066558104174067712.html
鏈家,28000,207㎡,盛德大廈 4室2廳 28000元,東城,和平裏,4室2廳2衛,中樓層(20層),"近地鐵,集中供暖,隨時看房",/zufang/BJ2049715273455910912.html
龍源易家,3500,26㎡,合租 · 海運倉小區 3室1廳,東城,東直門,3室1廳1衛,未知(6層),"限女生,限男生,獨立衛生間,租房節,近地鐵,精裝,獨立陽臺,集中供暖,免中介費,新上",/zufang/BJ2066335711790891008.html
...
``
房源信息抓取完成後保存到csv文件中,然後使用對數據進行分析。

5.房源價格分析:

老貓算了下,三個平臺數據加起來差不多7W套左右(鏈家數據和貝殼有重復,同一個房員可同時掛在鏈家與我愛我家中),所有應該到不了7W套。
我們使用分析模塊為Python中的matplotlib, pandas, seaborn, pyecharts;

5.1:分析北京各轄區的總的價格分布:

房東要給我漲800房租,生氣的我用Python抓取帝都幾萬套房源信息,我主動漲了1000。