上海的房租有多高?我用 Python 爬虫为你揭晓
0

此文首发于公众号 brucepk,点击这里 查看,如需转载,请联系作者。

阅读文本大概需要 7 分钟。

大家还记得你们刚来上海的时候租房的房租是多少吗?现在相比于那个时候,是不是涨了不少?上个月中介哄抢租赁房源的事件大家应该还没忘记。pk哥在上海,也是见证了房租稳步上涨的过程。很多网友感慨,以前是买不起房,现在是租房都租不起了。

今天,pk哥用 Python 爬虫给大家分析下上海的房租。我们用数据来看看上海的房租究竟有多高。

这次的租房房源数据来源于链家网,用 Python 收集数据后制作成可视化图形。

效果图

本次用 Python 爬取链家网的样本数据我把它做成了柱形图。从图中看到,有些区域的房源是比较少的,像崇明、金山、上海周边这三个区域提供的房源较少。

通过样本数据我提取出上海各区域的房租平均值。图中标出了最高房租和最低房租。

这个房租的平均值参考性不大,因为房租的多少还和房屋面积和户型有关。我们用词云图来看看出租的房源中的主要户型情况,字体越大表示此户型占的比例越大。

从户型词云图看得出来,出租的房源中最多的户型是 3 室 2 厅和 2 室 2 厅。如果和认识的朋友一起,租这种户型的房子也是一个不错的选择,这种户型的房子一般在小区,环境也不错。

所以,为了使数据更具有参考性,我把各区域房源每平米的月租平均值用 Python 计算出来画成了柱形图。图中标出了最高的每平米月租和最低的的每平米月租。最高的平均值是静安区的 160.79 元,最低的平均值是奉贤区的 29.77 元。

项目环境

语言:Python 3

编辑器:Pycharm

主要思路

1、用 Python 爬虫对链家网房源信息收集。

2、把房源信息按照自己需求整理成可视化图形。

出租房信息收集

出租房信息采集的来源是链家网,打开链家网页面,用 F12 打开页面的调试功能。页面信息的抓取用 requests 库就可以轻松获取。

代码分析

先把单个页面租房的信息提取出来以字典的形式保存。我提取的信息有出租房屋的标题、户型、面积、房租、每平米房租。把这些信息以字典的形式返回。部分主要代码如下。(左右滑动查看全部代码)

def RoomInfo(html):
    soup = BeautifulSoup(html, 'lxml')
    titles = soup.select('#house-lst div.info-panel h2 a')
    styles = soup.select('#house-lst div.info-panel div.col-1 div.where span.zone span')
    squares = soup.select('#house-lst div.info-panel div.col-1 div.where span.meters')
    prices = soup.select('#house-lst div.info-panel div.col-3 div.price span')
    data = []
    for ti, st, sq, pr, in zip(titles, styles, squares, prices):
        info = {}
        title = ti.get_text().strip()    # 出租房屋标题
        info['标题'] = title
        style = st.get_text().strip()    # 出租房屋户型
        info['户型'] = style
        square = sq.get_text().strip()[0:-2]   # 出租房屋面积
        info['面积(平方)'] = square
        price = pr.get_text().strip()    # 出租房屋房租
        info['房租(元/月)'] = price
        price_square = round(float(price)/float(square), 3)    # 出租房屋每平米房租
        info['每平方房租(元)'] = price_square
        data.append(info)
    return data

接下来把上面提取的信息保存在 csv 文件中,文件名称通过提取 url 中的元素作为获得,因为每个地区的出租房信息链接都是在后面加一个中文拼音,比如浦东。

一行表示一组房屋信息,列信息分别对应是上面函数获取的标题、户型、面积、房租、每平方房租,我把所有信息都保存在 E 盘的 「zufang」目录下,需要事先新建好目录,保存的文件部分截图如下。

实现把房源信息以 csv 文件形式存储功能的代码如下。(左右滑动查看全部代码)

def write2csv(url, data):
    name = url.split('/')[-3]
    print('正在把数据写入{}文件'.format(name))    # 以链接中的地区拼音给文件命名
    with open('E:\\zufang\\{}.csv'.format(name), 'a', newline='', encoding='utf-8-sig') as f:
        fieldnames = ['标题', '户型', '面积(平方)', '房租(元/月)', '每平方房租(元)']  # 控制列的顺序
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(data)
        print("写入成功")

对页面分页时我们需要判断页面有多少页,不同地区页面会显示该地区房源的数量,每个页面显示 30 个房源,所以基本情况是页面等于房源总数量除以 30,所有区域房源最大的页面是 100 页,但是有些地区房源数量除以 30 结果大于 100 页,不知道链家的多余的房源去哪里了,这里超过 100 就当 100 处理了,还有一种情况是有些地方房源比较少,不到 30 个,那么就只有一页的数据。

def get_page_num(url):
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    nums = soup.select('body div.wrapper div.main-box.clear div.con-box div.list-head.clear h2 span')
    for n in nums:
        total = int(n.get_text())
        if total < 30:
            num = 1
            return num
        else:
            num = total / 30
            if num > 100:
                num = 100
                return num
            else:
                return num

接下来获取不同区域的所有房源信息,包括浦东区、闵行区、宝山区、普陀区、杨浦区、长宁区、松江区、嘉定区、黄埔区、静安区、闸北区、虹口区、青浦区、奉贤区、金山区、崇明区、上海周边地区、地铁租房、所有房源。为了不给链家服务器造成太大的压力而导致 IP 被封,每爬取一页时我设置了随机等待时间。(左右滑动查看全部代码)

for area in ['pudong', 'minhang', 'baoshan', 'putuo', 'yangpu', 'changning', 'songjiang', 'jiading', 'huangpu',
             'jingan', 'zhabei', 'hongkou', 'qingpu', 'fengxian', 'jinshan', 'chongming', 'shanghaizhoubian',
             'ditiezufang', 'all']:
    base_url = 'https://sh.lianjia.com/zufang/{}/pg1/'.format(area)
    num = get_page_num(base_url)
    for page in range(1, int(num) + 1):
        url = 'https://sh.lianjia.com/zufang/{}/pg{}/'.format(area, page)
        html = get_html(url)
        data = RoomInfo(html)
        write2csv(url, data)
        time.sleep(int(format(random.randint(0, 5))))

数据可视化处理

接下来对获得的数据进行可视化处理,我拿对户型生成词云图举例,通过从保存的 csv 文件中获取需要列的信息并统计相同元素出现的次数,剔除无关信息后生成文章前面出现的户型词云图。

import csv
import os
from pyecharts import WordCloud

def all_list(arr):
    result = {}
    for i in set(arr):
        result[i] = arr.count(i)
    return result

os.chdir('E:\\zufang')
with open('all.csv', 'rt', encoding="utf-8") as csvfile:
    reader = csv.reader(csvfile)
    column = [row[1] for row in reader]
    result = all_list(column)
    result.pop('户型')    # 去掉字典中的无关信息

key = list(result.keys())
value = list(result.values())

wordcloud = WordCloud(width=1500, height=700)
wordcloud.add('', key, value, word_size_range=[20, 100])
wordcloud.render('E:\\pye\\style.html')   # 在指定目录下生成文件

其他的可视化图形也是同样的思路,不清楚可查看我之前发的各种可视化图形制作方法的文章:
Python让你的数据生成可视化图形

在公众号后台回复「房租」获取源码。

以梦为马,不负韶华

讨论数量: 2
fanyang

请问这个爬虫是否有做容错机制, 比如突然从某个点中断,重启程序如何记录错误

2周前

@fanyang 程序比较简单,没做容错机制,大佬可以自己试一下

1周前

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!