博主介绍:✌全网粉丝50W+,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战8年之久,选择我们就是选择放心、选择安心毕业✌
> 🍅想要获取完整文章或者源码,或者代做,拉到文章底部即可与我联系了。🍅

点击查看作者主页,了解更多项目!

🍅感兴趣的可以先收藏起来,点赞、关注不迷路,大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助同学们顺利毕业 。🍅

1、毕业设计:2026年计算机专业毕业设计选题汇总(建议收藏)✅

2、大数据毕业设计:2026年选题大全 深度学习 python语言 JAVA语言 hadoop和spark(建议收藏)✅

1、项目介绍

技术栈
Python为开发语言,采用Scrapy爬虫框架从贝壳租房网采集房源数据,后端使用Django框架处理业务逻辑与API接口,前端采用Vue框架构建交互界面,数据库存储采集到的租房信息,通过Echarts实现数据可视化展示,并结合推荐系统算法为用户提供个性化房源匹配。

功能模块
· 数据爬取模块
· 数据存储模块
· 用户注册登录模块
· 数据分析模块
· 可视化大屏展示模块
· 租房信息查询模块
· 个性化推荐模块
· 数据管理模块

项目介绍
本系统是一个基于Python的租房大数据分析可视化平台,旨在解决租房市场信息分散、选择低效的问题,为用户提供精准的租房参考与个性化推荐服务。系统通过Scrapy爬虫框架从贝壳租房网采集海量房源数据,经清洗整理后存入数据库,后端采用Django框架实现数据处理与业务逻辑,前端使用Vue框架构建用户交互界面,配合Echarts将分析结果以可视化大屏形式直观呈现。平台涵盖数据爬取、可视化分析、个性化推荐等核心功能,用户可通过注册登录进入系统,浏览房源朝向分布、区域热力地图、租房类型统计、楼层分析、价格分布等多维度可视化图表,在租房信息页面通过多条件筛选查询房源,查看房源详情页获取完整信息,同时系统基于用户行为数据通过推荐算法生成个性化房源推荐列表,为用户提供从房源查询到决策参考的全流程服务。

2、项目界面

(1)租房数据可视化大屏
该页面为租房数据爬虫推荐可视化系统的可视化分析界面,包含房屋朝向分析矩形图、房源数量分布热力地图、租房类型统计环形图、楼层类型分析折线图及房源价格分布柱状图,可从朝向、区域、类型、楼层、价格多维度直观展示租房数据特征与分布规律。
在这里插入图片描述

(2)租房推荐
该页面为租房数据爬虫推荐可视化系统的租房信息界面,提供标题、省份、城市、标签等多维度筛选搜索及多种排序方式,以卡片形式展示房源基础信息,同时右侧呈现算法推荐房源,可便捷查询与个性化推荐租房信息。
在这里插入图片描述

(3)租房数据详情页
该页面为租房数据爬虫推荐可视化系统的租房详情界面,展示房源的图片、基本信息、价格、位置、户型及配套设施等详细内容,同时右侧呈现相关推荐房源,可让用户全面了解房源信息并获取相似租房推荐。
在这里插入图片描述

(4)房屋数据
该页面为租房数据爬虫推荐可视化系统的租房详情界面,展示房源的户型图、基本信息、价格、位置、户型及配套设施等详细内容,同时右侧呈现相关推荐房源,可让用户全面了解房源布局与信息并获取相似租房推荐。
在这里插入图片描述

(5)注册登录界面
该页面为租房数据爬虫推荐可视化系统的登录界面,提供用户名与密码输入框,支持密码显示/隐藏功能,设有登录按钮与账号注册入口,可完成用户身份验证与新账号创建,保障系统访问的安全性。
在这里插入图片描述

(6)数据爬取页面
该页面为租房推荐系统的代码编辑与运行界面,上方展示基于用户历史浏览记录的推荐算法代码,下方控制台输出爬虫采集租房数据的日志,可实现租房数据的自动化爬取与个性化推荐逻辑的开发调试。
在这里插入图片描述

3、项目说明

一、技术栈说明
本系统以Python为核心开发语言,数据采集层采用Scrapy爬虫框架,从贝壳租房网自动化抓取房源信息。后端基于Django框架构建,负责处理业务逻辑、API接口交互及数据管理。前端使用Vue框架搭建,实现响应式用户界面与流畅的交互体验。数据存储方面,采集到的房源信息经过清洗整理后存入数据库。可视化层借助Echarts图表库,将数据分析结果以多种图表形式动态呈现。推荐模块结合协同过滤等算法,基于用户行为数据生成个性化房源推荐列表。

二、功能模块详细介绍
· 数据爬取模块
该模块基于Scrapy爬虫框架编写自动化采集脚本,实现对贝壳租房网房源数据的定向抓取。开发者可配置爬取规则与请求参数,采集内容包括房源标题、省份、城市、具体地址、价格、户型、面积、朝向、楼层、标签、图片链接、配套设施等字段。模块支持断点续爬与增量更新,控制台实时输出采集日志,爬取到的原始数据经初步清洗后存入数据库,为平台提供基础数据支撑。

· 数据存储模块
采集到的房源原始数据经过格式统一、去重、异常值过滤等清洗操作后,按照预先设计的数据表结构存入数据库。模块通过Django的ORM框架实现数据的持久化管理,支持后续数据分析、可视化展示与推荐算法调用时的高效查询与读取,确保数据的一致性与完整性。

· 用户注册登录模块
系统前端提供统一的用户登录入口,包含用户名与密码输入框、登录按钮及注册链接。新用户可通过注册功能创建个人账号,后端对用户密码进行加密存储,实现身份验证与会话管理。页面支持密码显示/隐藏功能,提升用户输入体验。该模块保障系统访问安全,确保可视化分析与个性化推荐功能仅对授权用户开放。

· 数据分析模块
模块基于数据库中的房源数据,通过Django后端进行多维度统计与分析计算。分析维度包括房源朝向分布、区域房源数量、租房类型占比、楼层分布特征、价格区间分布等。分析结果以结构化数据形式输出,供可视化模块调用,为后续图表呈现提供数据基础。

· 可视化大屏展示模块
作为系统的核心展示界面,该模块将多维度分析结果集成于单一可视化大屏。页面包含房屋朝向分析矩形图、房源数量分布热力地图、租房类型统计环形图、楼层类型分析折线图及房源价格分布柱状图。用户可在一屏之内直观对比房源在朝向、区域、类型、楼层、价格等多个维度的分布特征与关联规律,快速把握租房市场整体状况。

· 租房信息查询模块
该模块以卡片列表形式呈现房源基础信息,页面提供标题、省份、城市、标签等多维度筛选搜索功能,支持多种排序方式(如价格、评分、距离等)。用户可输入关键词或选择筛选条件快速定位目标房源。点击卡片可进入详情页,查看房源的图片轮播、基本信息、价格、位置、户型、配套设施等详细内容,全面了解房源情况。

· 个性化推荐模块
模块基于用户历史浏览记录、搜索行为及收藏数据,通过协同过滤推荐算法分析用户偏好特征,生成个性化房源推荐列表。推荐结果在租房信息页面右侧区域展示,同时在房源详情页呈现相关相似房源推荐。模块通过Django后端实现推荐逻辑,结合用户行为数据实时计算,为用户推送符合其兴趣偏好的房源选项,提升选择效率与用户体验。

· 数据管理模块
该模块面向系统管理员,提供后台数据管理功能。管理员可对采集到的房源数据进行查看、编辑、删除等操作,也可对用户信息进行维护管理。模块通过Django admin后台界面实现,支持数据批量处理与状态监控,保障平台数据的准确性与规范性。

三、项目总结
本系统经过需求分析、技术选型、模块开发与集成测试四个阶段,成功构建了一个基于Python的租房大数据可视化推荐平台。系统以贝壳租房网为目标数据源,通过Scrapy爬虫框架实现海量房源数据的自动化采集,依托Django后端完成数据处理与业务逻辑,借助Vue前端构建流畅交互界面,利用Echarts将多维度分析结果以可视化大屏形式直观呈现,并结合推荐算法为用户提供个性化房源匹配。平台涵盖数据爬取、存储管理、用户认证、多维度分析、可视化展示、房源查询、智能推荐、后台维护八大功能模块,为用户提供从房源查询到决策参考的全流程服务,有效解决租房市场信息分散与选择低效的问题,验证了数据爬虫、可视化技术与推荐算法在租房领域的应用价值。

4、核心代码


from .models import *
import json
from django.http.response import HttpResponse
from django.shortcuts import render
from django.http import JsonResponse
from datetime import datetime, time
from django.core.paginator import Paginator
from django.db.models import Q
import simplejson
from collections import Counter
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.charts import Map, Grid, Bar, Line, Pie, TreeMap
from pyecharts.faker import Faker
from pyecharts.commons.utils import JsCode
from pyecharts.options.charts_options import MapItem
from django.db.models import Q, Count, Avg, Min, Max


def to_dict(l, exclude=tuple()):
    # 将数据库模型 变为 字典数据 的工具类函数
    def transform(v):
        if isinstance(v, datetime):
            return v.strftime("%Y-%m-%d %H:%M:%S")
        return v

    def _todict(obj):
        j = {
            k: transform(v)
            for k, v in obj.__dict__.items()
            if not k.startswith("_") and k not in exclude
        }
        return j

    return [_todict(i) for i in l]


def unique_fields(request):
    body = request.json
    field = body.get("field")
    data = [i[0] for i in Rental.objects.values_list(field).distinct()]
    return JsonResponse(data, safe=False)


def get_list(request):
    # 列表
    body = request.json
    pagesize = body.get("pagesize", 10)
    page = body.get("page", 1)
    orderby = body.get("orderby", "-id")
    notin = ["pagesize", "page", "total", "orderby"]
    query = {
        k: v for k, v in body.items() if k not in notin and (v != "" and v is not None)
    }
    q = Q(**query)
    objs = Rental.objects.filter(q).order_by(orderby)
    paginator = Paginator(objs, pagesize)
    pg = paginator.page(page)
    result = to_dict(pg.object_list)
    return JsonResponse(
        {
            "total": paginator.count,
            "result": result,
        }
    )


def get_detail(request):
    # 详情
    body = request.json
    id = body.get("id")
    o = Rental.objects.get(pk=id)
    his = History.objects.filter(userId=request.user.id).order_by("-createTime").first()
    if not (his and his.rentalId == o.id):
        History(userId=request.user.id, rentalId=o.id).save()
    return JsonResponse(to_dict([o])[0])


def history_recommand(request):
    rentalIds = (
        History.objects.filter(userId=request.user.id)
        .values_list("rentalId")
        .distinct()
    )
    rentals = []
    # 根据历史查看记录推荐
    if rentalIds:
        rentalIds = [i[0] for i in rentalIds]
        location = [
            i[0]
            for i in Rental.objects.filter(id__in=rentalIds).values_list("location")
        ]
        locations = ["-".join(i.split("-")[:2]) for i in location]
        most_common_cates = list(dict(Counter(locations).most_common(2)).keys())
        q = Q()
        for i in most_common_cates:
            q |= Q(location__icontains=i)
        rentals = Rental.objects.filter(q).order_by("?")[:5]
    # 没有记录则随机推荐
    else:
        rentals = Rental.objects.order_by("?")[:5]
    return JsonResponse(to_dict(rentals), safe=False)


def type_pie(request):
    data = {
        i["type"]: i["count"]
        for i in Rental.objects.values("type").annotate(count=Count("id"))
        if "租" in i["type"]
    }
    # 用饼图展示数据
    c = (
        Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
        .add(
            "",
            list(data.items()),
            label_opts=opts.LabelOpts(is_show=False),
            radius=["40%", "75%"],
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(title="租房类型统计", pos_left="40%"),
            legend_opts=opts.LegendOpts(
                type_="scroll", pos_right="80%", orient="vertical"
            ),
        )
    )
    # 返回数据
    return HttpResponse(c.dump_options(), content_type="application/json")


def orientation_map(request):
    data = [
        {"name": i["orientation"], "value": i["count"]}
        for i in Rental.objects.values("orientation").annotate(count=Count("id"))
    ]

    # 用饼图展示数据
    c = (
        TreeMap(init_opts=opts.InitOpts(width="1280px", height="720px"))
        .add(
            series_name="option",
            data=data,
            visual_min=300,
            leaf_depth=1,
            # 标签居中为 position = "inside"
            label_opts=opts.LabelOpts(position="inside"),
        )
        .set_global_opts(
            legend_opts=opts.LegendOpts(is_show=False),
            title_opts=opts.TitleOpts(title="房屋朝向分析", pos_left="leafDepth"),
        )
    )
    # 返回数据
    return HttpResponse(c.dump_options(), content_type="application/json")


def level_bar(request):
    data = {
        i["level"]: i["count"]
        for i in Rental.objects.values("level").annotate(count=Count("id"))
        if i["level"]
    }

    # 用柱状图展示统计数据
    c = (
        Bar()
        .add_xaxis([i[0] for i in data.items()])
        .add_yaxis(
            "",
            [i[1] for i in data.items()],
            label_opts=opts.LabelOpts(is_show=False),
            bar_max_width=50,
        )
        .reversal_axis()
        .set_global_opts(
            title_opts=opts.TitleOpts(title="楼层类型分析"),
            # datazoom_opts=opts.DataZoomOpts(orient="vertical"),
            yaxis_opts=opts.AxisOpts(
                type_="category",
                axispointer_opts=opts.AxisPointerOpts(is_show=True, type_="shadow"),
            ),
        )
    )
    # 返回数据
    return HttpResponse(c.dump_options(), content_type="application/json")


def price_bar(request):
    data = {}
    data["1000以下"] = Rental.objects.filter(price__lte=1000).count()
    data["1000-2000"] = Rental.objects.filter(price__gte=1000, price__lte=2000).count()
    data["2000-3000"] = Rental.objects.filter(price__gte=2000, price__lte=3000).count()
    data["3000-4000"] = Rental.objects.filter(price__gte=3000, price__lte=4000).count()
    data["4000-5000"] = Rental.objects.filter(price__gte=4000, price__lte=5000).count()
    data["5000-6000"] = Rental.objects.filter(price__gte=5000, price__lte=6000).count()
    data["6000-7000"] = Rental.objects.filter(price__gte=6000, price__lte=7000).count()
    data["7000以上"] = Rental.objects.filter(price__gte=7000).count()

    # 用柱状图展示统计数据
    c = (
        Bar()
        .add_xaxis([i[0] for i in data.items()])
        .add_yaxis(
            "",
            [i[1] for i in data.items()],
            label_opts=opts.LabelOpts(is_show=False),
            bar_max_width=50,
            color="#5689ff",
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(title="房源价格分布"),
            # datazoom_opts=opts.DataZoomOpts(orient="vertical"),
            xaxis_opts=opts.AxisOpts(
                type_="category",
                axispointer_opts=opts.AxisPointerOpts(is_show=True, type_="shadow"),
            ),
        )
    )
    # 返回数据
    return HttpResponse(c.dump_options(), content_type="application/json")


def province_map(request):
    data = {
        i["province"] + "省": i["count"]
        for i in Rental.objects.values("province").annotate(count=Count("id"))
    }
    dd = [MapItem(name=i[0], value=i[1]) for i in data.items()]
    m = (
        Map()
        .add("房源数量", dd, "china", is_roam=False, is_map_symbol_show=False)
        .set_global_opts(
            title_opts=opts.TitleOpts(
                title="房源数量分布",
            ),
            visualmap_opts=opts.VisualMapOpts(
                max_=1000,
                is_piecewise=False,
            ),
            legend_opts=opts.LegendOpts(
                is_show=False, textstyle_opts=opts.TextStyleOpts(color="white")
            ),
        )
    )
    return HttpResponse(m.dump_options(), content_type="aplication/text")



5、源码获取方式

🍅由于篇幅限制,获取完整文章或源码、代做项目的,查看我的【用户名】、【专栏名称】、【顶部选题链接】就可以找到我啦🍅

感兴趣的可以先收藏起来,点赞、关注不迷路,下方查看👇🏻获取联系方式👇🏻

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐