[编程经验] 链家23个全国主要城市的现房数据分析

今天起来看到一个公众号发的推文,分析了链家上面成都的房价数据,自己好奇也玩了一把,收集了全国23个主要城市的在售房产数据,并作了对比,拿出来跟大家分享。涉及的城市有广州,大连,杭州,济南,石家庄,武汉,长沙,深圳,郑州,天津,佛山,北京,上海,惠州,沈阳,太原,厦门,重庆,珠海,合肥,成都,中山,南京,西安。爬虫写的比较笨,大神勿喷。

先放一张条形图,感受一下房价。

1. 数据爬取

打开链家的新房主页,任意选择一个城市,然后按楼盘来查找,就是下面这个。

然后我们主要关心的数据有楼盘的名字,售卖状态,地点以及价格等。然后查看网页源码之后发现,我们想要的数据在resblock-list-wrapper这个class里面。所以首先取到这个class下面的全部内容,然后再挨个提取我们想要的数据。

代码如下

import urllib.request
from bs4 import BeautifulSoup
from tqdm import trange
import pandas as pd
import requests
import os
import numpy as np
import matplotlib.pyplot as plt
from pylab import mpl

citys = {'bj': "北京", 'xa': "西安", 'cd': "成都",
         'cq': "重庆", 'sh': "上海", 'sz': "深圳",
         'gz': "广州", 'hz': "杭州", 'dl': "大连",
         'nj': "南京", 'sjz': "石家庄", 'sy': "沈阳",
         'tj': "天津", 'wh': "武汉", 'xm': "厦门",
         'cs': '长沙', 'zz': '郑州', 'ty': '太原',
         'hf': '合肥', 'fs': "佛山", 'hui': '惠州',
         'jn': '济南', 'zs': "中山"}

print(len(citys))
mpl.rcParams['font.sans-serif'] = ['FangSong']
mpl.rcParams['axes.unicode_minus'] = False

for city in citys.keys():
    save_data = []
    for i in trange(120):
        url = "https://{}.fang.lianjia.com/" \
              "loupan/pg{}/".format(city, i)
        print(requests.get(url).status_code)
        if requests.get(url).status_code != 200:
            continue
        req = urllib.request.Request(url)
        req.add_header("User-Agent",
                       "Mozilla/5.0 (Windows NT 6.1; WOW64) "
                       "AppleWebKit/537.36 (KHTML, like Gecko)"
                       " Chrome/45.0.2454.101 Safari/537.36")
        req.add_header("Accept", "*/*")
        req.add_header("Accept-Language", "zh-CN,zh;q=0.8")

        data = urllib.request.urlopen(req)
        html = data.read().decode('utf-8')

        soup = BeautifulSoup(html, "lxml")
        resp = soup.findAll('ul',
                            attrs={
                                'class': 
                                'resblock-list-wrapper'})
        resp = resp[0]
        resp = resp.findAll('li', attrs={'class': 
                                    'resblock-list'})
        for i in range(len(resp)):
            housenames = resp[i].findAll(
                'div', attrs={'class': 'resblock-name'})
            housename = housenames[0].findAll(
                'a', attrs={'target': '_blank'})[0].text
            herf = housenames.get('herf')
            print(herf)
            exit(1)
            try:
                housenames = resp[i].findAll(
                    'div', attrs={'class': 'resblock-name'})
                housename = housenames[0].findAll(
                    'a', attrs={'target': '_blank'})[0].text
                herf = housenames.get('herf')
                print(herf)
                resblocktype = housenames[0].findAll(
                    'span', attrs={'class': 
                    'resblock-type'})[0].text
                salestatus = housenames[0].findAll(
                    'span', attrs={'class':
                     'sale-status'})[0].text
            except:
                continue
            try:
                resblocklocation = resp[i].findAll(
                    'div', attrs={'class': 
                    'resblock-location'})
                addressinfolist = \
                    resblocklocation[0].text.
                    replace("\n", "")
                quyu, address, addressinfo = \
                    addressinfolist.split("/")[0], \
                    addressinfolist.split("/")[1], \
                    addressinfolist.split("/")[2]
            except:
                continue
            try:
                resblockroom = resp[i].findAll(
                    'a', attrs={'class': 'resblock-room',
                                'target': '_blank'})[
                    0].text.replace("\n", "")
            except:
                continue
            try:
                resblockarea = resp[i].findAll(
                    'div', attrs={'class': 'resblock-area'})
                    [0].\
                    text.replace("\n", "").
                    replace("建面 ", "")
            except:
                continue
            try:
                resblockprice = resp[i].findAll(
                    'div', attrs={'class': 'main-price'})[0]
                priceinfo = resblockprice.findAll(
                    'span', attrs={'class': 'number'})[0].
                    text
            except:
                continue
            try:
                secondprice = resp[i].findAll(
                    'div', attrs={'class': 'second'})[0].\
                    text.replace("总价", "").
                    replace("万/套起", "")
            except:
                continue
            rows = {'housename': housename, 
                    'resblocktype': resblocktype,
                    'salestatus': salestatus,
                    'address': address,
                    'addressinfo': addressinfo,
                    'resblockroom': resblockroom,
                    'resblockarea': resblockarea,
                    'priceinfo': priceinfo, 
                    'secondprice': secondprice}
            save_data.append(rows)

    df = pd.DataFrame(save_data)
    df.to_csv("./datasets/{}.csv".format(city),
              line_terminator="\n", index=None)

2. 数据分析

然后分析每平米的价格数据,做个条形图

def analyse():
    path = './datasets'
    mean_price = []
    for file in os.listdir(path):
        filename = os.path.join(path, file)
        data = pd.read_csv(filename, 
            usecols=['priceinfo']).values

        prices = []
        for x in data:
            if str(x[0]).isdigit():
                prices.append(int(x[0]))

        pricesmean = np.mean(prices)
        rows = {'city': citys[file.split(".")[0]],
                'meanprice': pricesmean}
        mean_price.append(rows)
    df = pd.DataFrame(mean_price)
    df = df.sort_values(by='meanprice', ascending=False)
    labels = df['city']
    price = df['meanprice']
    width = 0.5
    ind = np.linspace(1, 23, 23)
    fig = plt.figure(dpi=600)
    ax = fig.add_subplot(111)
    ax.bar(ind - width / 2, price, width, color='green')
    ax.set_xticks(ind)
    ax.set_xticklabels(labels)
    ax.set_ylabel('新房均价')
    ax.set_title('全国23个大城市新房平均价格',
                 bbox={'facecolor': '0.8', 'pad': 5})
    plt.grid(True)
    plt.xticks(rotation=45)
    plt.savefig("bar.jpg")
    plt.close()

然后就是这个图了

从这个图可以看到,房价最高的不是北京和上海,而是杭州,并且成都的房价要低于西安,这个是我之前没有想到的。

花了大半天的时间,做了这些,然后链家里面有价值的数据我觉得还有房源的评论数据,这个数据其实也不难爬,可以给大家看看。我们点房源的评论,网页就跳转到这个页面,url后面跟的这个是什么呢?

回到上一页,点楼盘名称,然后查看源代码,然后看到这个herf后面跟着的就是评论的url后面的。

所以想要爬取评论数据,只要提取出这个herf,然后跟在前面的url后面就可以了。然后提取具体的评论语料就简单了哈。

有需要的童鞋可以下载本文代码:

链接:https://pan.baidu.com/s/1dOTXTk 密码:i5uh

原文发布于微信公众号 - 机器学习和数学(ML_And_Maths)

原文发表时间:2018-02-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏黑泽君的专栏

壁挂式空调漏水怎么办?如何解决?

一:安装不牢固:室内机安装膨胀螺丝未打稳,安装不牢固影响平衡,导致排水管引出一侧位置偏高,造成排水困难,从而发生空调机机体滴水现象。

38640
来自专栏程序员互动联盟

【程序员故事】搞笑篇

1、我真想开个程序员餐厅了,我当老板娘,进门时先写代码再进,一楼餐厅分C包间、java包间、linux/unix包间。搞开源软件的就坐大厅里,搞Ruby的上二楼...

28330
来自专栏睿哥杂货铺

我的2017年度盘点

https://www.gitbook.com/book/riboseyim/linux-perf-master/details

22480
来自专栏机器人网

工业机器人伺服结构和原理

伺服的结构是怎样的?一个最简易的伺服控制单元,就是一个伺服电机加伺服控制器,今天就来解析下伺服电机与伺服控制器。 电机动作的原理 右手螺旋法则(安培定则)——通...

34750
来自专栏FreeBuf

极客DIY:教你做一个简单的“太阳能”移动电源

在这篇分享中,我将向大家一步一步的展示如何手工制作一个简单的太阳能移动电源。同时因为我个人的喜好,漂亮且艺术感十足的木质外在的制作过程也会包含其中。 类似的分享...

21590
来自专栏练小习的专栏

网站508规范(译)

出处:蓝色理想和玩·艺|中国同步发布 Guide to the Section 508 Standards for Electronic and Informa...

20150
来自专栏知晓程序

举报!这里有人,在光天化日之下聚众撸猫

但并不是每个人都有机会成为「猫奴」。这时候,你需要 「吸猫君」 ,来帮你开启「云吸猫」的生活。

9720
来自专栏大神带我来搬砖

记一次高级软件架构师的铩羽而归

前几天女朋友笔记本电脑开机后进不了系统了,鉴于我天天告诉她要用宏来处理Excel,于是耳提面命,让我来修修。当时我想,这有何难,哪有程序员修不了电脑的?正如马谡...

36980
来自专栏牛客网

19届前端实习生面经

18000
来自专栏大数据文摘

MIT:助力器官移植,新技术让死亡心脏重新“复活”

19680

扫码关注云+社区

领取腾讯云代金券