ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Django+Python+Echarts招聘数据可视化分析系统搭建指南

Django+Python+Echarts招聘数据可视化分析系统搭建指南 简介这份资源是DjangoPythonEcharts招聘数据可视化分析项目的完整源码面向计算机相关专业学生、毕业设计或期末大作业开发者帮助快速搭建一套可运行的数据分析展示系统。项目以Django为后端框架Python负责数据采集与处理Echarts完成前端图表渲染覆盖招聘数据清洗、统计与可视化呈现等典型环节适合作为课程设计参考或二次开发基础。压缩包共537个文件约32.32MB包含109个html页面、102个js脚本、40个py源码、24个css样式及75个gif素材另有dll、xml、exe等运行依赖与配置项结构完整、模块划分清晰。目前已有396人学习下载且该作品以96分高分通过期末考核。下载后简单部署即可运行读者可据此掌握Django项目组织方式、Echarts图表配置与招聘数据分析思路节省从零搭建的时间成本。1. 招聘数据可视化大作业从一份 zip 到能跑起来的分析系统每年期末季总有一批同学被招聘数据可视化分析这个大作业卡住。题目本身不复杂——爬一批招聘岗位数据做几个图表写个分析结论。但真动手时问题就来了数据从哪来、用什么存、图表怎么跟前端对接、Django 里怎么组织这些代码。很多人最后交上去的东西要么是几张静态截图拼的 PPT要么是跑不起来的半成品。这份以 Django Python Echarts 为核心的招聘数据可视化分析源码解决的正是这条链路Python 负责数据采集和清洗Django 提供 Web 框架和数据接口Echarts 在前端把薪资分布、学历要求、城市热度这些维度画出来。它适合两类人——赶期末大作业的学生以及想用一个完整小项目练手 Django 全栈的入门者。下面我按实际搭建顺序把每个环节拆开讲清楚。2. 环境搭建与 Django 项目骨架别在第一步就翻车2.1 Python 与依赖安装的稳妥路径很多人第一步就卡在 python 安装上。Windows 用户去 python 官网下载安装包时记得勾选Add Python to PATH否则后面命令行里敲 python 会提示找不到命令。装完之后验证一下python --version pip --version如果 pip 版本太旧先升级再装依赖能避免不少包解析失败的问题python -m pip install --upgrade pip接下来装 Django 和数据处理常用的库。招聘数据可视化这个场景核心依赖就几个Django 本身、pandas 做数据清洗、requests 或 scrapy 做采集、pymysql 或 mysqlclient 连数据库。pip install django pandas requests pymysql这里有个血泪经验mysqlclient 在 Windows 上编译经常报错新手直接用 pymysql 更省事在 Django 的__init__.py里加两行伪装成 MySQLdb 就行# 项目 __init__.py import pymysql pymysql.install_as_MySQLdb()参数说明install_as_MySQLdb()的作用是让 Django 以为你在用 MySQLdb实际底层走的是纯 Python 的 pymysql省去编译环节。如果你用 SQLite 做开发库这一步可以跳过但期末作业一般要求 MySQL提前配好省得后期迁移。2.2 创建 Django 项目与 app 的标准动作环境好了之后创建项目和 app。django 创建 app 这个操作新手容易搞混目录层级记住先建项目再在项目根目录下建 app。django-admin startproject recruitment_viz cd recruitment_viz python manage.py startapp jobs建完之后目录结构是这样的recruitment_viz/ ├── manage.py ├── recruitment_viz/ │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── jobs/ ├── models.py ├── views.py └── ...接着在settings.py里注册 app配置数据库连接和模板路径# settings.py 关键片段 INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, jobs, # 注册我们的 app ] DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: recruitment_db, USER: root, PASSWORD: your_password, HOST: 127.0.0.1, PORT: 3306, } } TEMPLATES [ { BACKEND: django.template.backends.django.DjangoTemplates, DIRS: [BASE_DIR / templates], # 模板目录 APP_DIRS: True, OPTIONS: { context_processors: [ django.template.context_processors.debug, django.template.context_processors.request, django.contrib.auth.context_processors.auth, django.contrib.messages.context_processors.messages, ], }, }, ]参数说明NAME是数据库名需要提前在 MySQL 里CREATE DATABASE recruitment_db。DIRS指向项目根目录下的 templates 文件夹Echarts 的 HTML 模板放这里。APP_DIRS: True表示也会去每个 app 下的 templates 目录找模板两种方式都行建议统一放项目级 templates方便管理。配置完执行迁移把 Django 自带的表建起来python manage.py migrate python manage.py createsuperusercreatesuperuser是建后台管理员账号后面往数据库里导数据、检查数据对不对都靠这个后台。到这里骨架就搭好了能跑起来看到 Django 的欢迎页说明环境没问题。3. 数据采集与模型设计招聘数据怎么存才合理3.1 招聘数据字段的取舍做招聘数据可视化第一步要想清楚存哪些字段。常见做法是采集岗位名称、公司名称、薪资范围、工作城市、学历要求、经验要求、公司规模、岗位描述这几项。字段不是越多越好采集字段太多清洗成本翻倍而且很多字段最后根本用不上。我一般会先定一个最小可用字段集对应 Django 的 model# jobs/models.py from django.db import models class JobInfo(models.Model): job_name models.CharField(max_length200, verbose_name岗位名称) company models.CharField(max_length200, verbose_name公司名称) salary models.CharField(max_length100, verbose_name薪资范围) city models.CharField(max_length50, verbose_name工作城市) education models.CharField(max_length50, verbose_name学历要求) experience models.CharField(max_length50, verbose_name经验要求) company_size models.CharField(max_length50, verbose_name公司规模) publish_date models.DateField(nullTrue, verbose_name发布时间) class Meta: db_table job_info verbose_name 招聘信息 def __str__(self): return self.job_name参数说明salary用 CharField 而不是数值类型因为招聘网站上的薪资经常是15-25K·13薪这种格式直接存字符串后面在 Python 里解析成最低和最高两个数值。publish_date允许为空有些采集源拿不到发布时间。db_table指定表名方便和采集脚本对接。3.2 采集脚本与数据入库采集部分如果只是期末作业用 requests BeautifulSoup 抓几个页面的数据就够了不需要上 scrapy 那么重。核心逻辑是请求列表页拿到详情链接再逐个请求详情页解析字段最后批量写入数据库。# scripts/fetch_jobs.py import os import django import requests from bs4 import BeautifulSoup os.environ.setdefault(DJANGO_SETTINGS_MODULE, recruitment_viz.settings) django.setup() from jobs.models import JobInfo def parse_salary(salary_text): 把 15-25K 解析成 (15, 25)解析失败返回 (0, 0) try: salary_text salary_text.replace(K, ).replace(k, ) low, high salary_text.split(-) return float(low), float(high) except Exception: return 0, 0 def save_job(item): 单条数据入库用 get_or_create 避免重复 JobInfo.objects.get_or_create( job_nameitem[job_name], companyitem[company], defaults{ salary: item[salary], city: item[city], education: item[education], experience: item[experience], company_size: item[company_size], } ) if __name__ __main__: # 这里替换成实际的目标页面 url https://example.com/jobs?page1 headers {User-Agent: Mozilla/5.0} resp requests.get(url, headersheaders, timeout10) soup BeautifulSoup(resp.text, html.parser) # 解析逻辑根据实际页面结构调整 for card in soup.select(.job-card): item { job_name: card.select_one(.job-title).text.strip(), company: card.select_one(.company-name).text.strip(), salary: card.select_one(.salary).text.strip(), city: card.select_one(.city).text.strip(), education: card.select_one(.education).text.strip(), experience: card.select_one(.experience).text.strip(), company_size: card.select_one(.company-size).text.strip(), } save_job(item) print(采集完成)逻辑说明脚本开头设置DJANGO_SETTINGS_MODULE并调用django.setup()这样脱离 Django 命令行也能用 ORM。parse_salary把薪资字符串转成数值后面画薪资分布图要用。get_or_create用岗位名 公司名做去重键重复采集不会产生脏数据。参数说明timeout10防止请求卡死headers里的 User-Agent 必须带否则很多站点直接返回 403。实际采集时记得加time.sleep(1)控制频率别把人家服务器打挂了。数据入库后去 Django admin 后台注册一下 model方便查看# jobs/admin.py from django.contrib import admin from .models import JobInfo admin.register(JobInfo) class JobInfoAdmin(admin.ModelAdmin): list_display (job_name, company, salary, city, education) search_fields (job_name, company) list_filter (city, education)注册完访问/admin用之前创建的超级用户登录就能看到采集进来的数据了。这一步很关键数据不对后面图表全是错的先在这里肉眼检查一遍。4. 数据接口与 Echarts 对接图表数据从哪来4.1 用 Django 视图输出 JSON 接口Echarts 需要的是 JSON 格式的数据所以 Django 这边要写几个接口把数据库里的数据聚合好返回。常见做法是用JsonResponse配合 ORM 的values和annotate做分组统计。# jobs/views.py from django.http import JsonResponse from django.db.models import Count, Avg from .models import JobInfo def city_distribution(request): 城市岗位数量分布用于柱状图 data (JobInfo.objects .values(city) .annotate(countCount(id)) .order_by(-count)[:10]) result { cities: [item[city] for item in data], counts: [item[count] for item in data], } return JsonResponse(result) def education_distribution(request): 学历要求分布用于饼图 data (JobInfo.objects .values(education) .annotate(countCount(id)) .order_by(-count)) result [{name: item[education], value: item[count]} for item in data] return JsonResponse(result, safeFalse) def salary_by_experience(request): 不同经验要求的平均薪资用于折线图 data (JobInfo.objects .values(experience) .annotate(avg_salaryAvg(salary_numeric)) .order_by(experience)) result { experiences: [item[experience] for item in data], salaries: [round(item[avg_salary], 1) if item[avg_salary] else 0 for item in data], } return JsonResponse(result)逻辑说明values(city).annotate(countCount(id))等价于 SQL 的GROUP BY city按城市分组统计岗位数。order_by(-count)[:10]取前 10 个城市避免图表太挤。education_distribution返回的格式是 Echarts 饼图直接能用的[{name, value}]结构所以safeFalse允许返回列表。参数说明salary_numeric是我在 model 里额外加的一个数值字段采集时用parse_salary算出来存进去方便做平均薪资统计。如果不想加字段也可以在 Python 里现算但数据量大时性能差。4.2 Echarts 前端渲染与接口联调接口有了前端页面用 Echarts 渲染。先在模板里引入 Echarts注意用国内 CDN 或者把 echarts.min.js 下载到 static 目录别依赖不稳定的外链。!-- templates/city_chart.html -- !DOCTYPE html html head meta charsetutf-8 title城市岗位分布/title script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script /head body div idcityChart stylewidth: 900px; height: 500px;/div script var chart echarts.init(document.getElementById(cityChart)); fetch(/api/city_distribution/) .then(res res.json()) .then(data { chart.setOption({ title: { text: 热门城市岗位数量 TOP10 }, tooltip: { trigger: axis }, xAxis: { type: category, data: data.cities, axisLabel: { rotate: 30 } }, yAxis: { type: value, name: 岗位数 }, series: [{ type: bar, data: data.counts, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #83bff6 }, { offset: 1, color: #188df0 } ]) } }] }); }); /script /body /html逻辑说明echarts.init绑定 DOM 容器fetch请求 Django 接口拿到数据后setOption渲染。柱状图用LinearGradient做渐变色这是 echarts 柱状图设置渐变色最常见的写法比纯色好看不少。axisLabel.rotate: 30解决城市名太长重叠的问题这是 python 画图横坐标太密集的同类问题Echarts 里靠旋转角度解决。参数说明trigger: axis表示鼠标悬停显示整条轴的数据柱状图常用。type: category是类目轴对应城市名type: value是数值轴对应岗位数。饼图的话把 series 的 type 改成pie数据直接用[{name, value}]格式中间的字通过title或label配置。路由配置别忘了# recruitment_viz/urls.py from django.contrib import admin from django.urls import path from jobs import views urlpatterns [ path(admin/, admin.site.urls), path(api/city_distribution/, views.city_distribution), path(api/education_distribution/, views.education_distribution), path(api/salary_by_experience/, views.salary_by_experience), ]联调时如果图表空白先打开浏览器 F12 看 Network 里接口返回了什么再看 Console 有没有报错。十有八九是接口返回的数据结构和 Echarts 期望的对不上或者 JSON 序列化时遇到日期类型报错。5. 避坑与排查这些坑我替你踩过了5.1 数据采集返回 403 或空数据现象requests 请求返回状态码 403或者返回的 HTML 里解析不出任何岗位卡片。原因目标站点做了反爬检查 User-Agent 是否缺失或者请求频率太高被临时封了 IP。解决请求头里补全 User-Agent、Referer采集循环里加time.sleep(1)到time.sleep(3)的随机延迟。如果还是不行换一个采集目标期末作业没必要死磕一个反爬严格的站点。5.2 Django 迁移时报 mysqlclient 编译错误现象执行python manage.py migrate时报错提示缺少 Visual C 编译环境或 mysql_config not found。原因mysqlclient 是 C 扩展Windows 上需要编译工具链Linux 上需要 mysql 开发库。解决改用 pymysql在项目__init__.py里加pymysql.install_as_MySQLdb()。Linux 上如果坚持用 mysqlclient先apt install default-libmysqlclient-dev再装。5.3 Echarts 图表不显示或显示空白现象页面加载了容器有大小但图表区域一片空白。原因常见有三种——容器没有设置宽高、Echarts 初始化时 DOM 还没渲染完、接口数据格式不对。解决容器必须显式设置width和height不能靠 CSS 撑开。初始化放在DOMContentLoaded之后或者把 script 放 body 末尾。接口数据用console.log打出来对照 Echarts 官方示例的数据结构检查。5.4 薪资字段解析报错导致入库中断现象采集脚本跑到某一条数据时抛异常整个脚本挂掉。原因薪资格式不统一有的写面议有的写15K以上split(-)直接崩。解决parse_salary里用 try-except 包住解析失败返回(0, 0)并在入库前过滤掉薪资为 0 的异常数据。采集脚本里每条数据的处理都单独 try-except一条失败不影响整体。5.5 中文乱码问题现象数据库里存的中文显示成问号或者页面上图表标题乱码。原因数据库字符集不是 utf8mb4或者连接时没指定字符集。解决建库时用CREATE DATABASE recruitment_db CHARACTER SET utf8mb4Django 数据库配置里加OPTIONS: {charset: utf8mb4}。模板文件保存为 UTF-8 编码HTML 里声明meta charsetutf-8。6. 让图表真正有分析价值三个进阶技巧6.1 薪资区间分桶而不是直接画原始值直接画每个岗位的薪资柱子密密麻麻看不出规律。更好的做法是把薪资分桶比如 0-5K、5-10K、10-15K、15-20K、20K 以上统计每个区间的岗位数量。这样出来的柱状图能一眼看出市场薪资集中在哪个区间。def salary_range_distribution(request): 薪资区间分布 bins [(0, 5), (5, 10), (10, 15), (15, 20), (20, 999)] labels [0-5K, 5-10K, 10-15K, 15-20K, 20K以上] counts [] for low, high in bins: count JobInfo.objects.filter( salary_low__gtelow, salary_low__lthigh ).count() counts.append(count) return JsonResponse({labels: labels, counts: counts})参数说明salary_low是采集时解析出来的最低薪资数值字段。分桶边界可以根据实际数据分布调整如果大部分岗位在 10-20K就把这个区间拆细一点。6.2 用地图展示城市分布Echarts 中国地图比柱状图更直观但需要引入地图的 JSON 数据。常见做法是下载 china.json 放到 static 目录注册地图后渲染。fetch(/static/map/china.json) .then(res res.json()) .then(mapData { echarts.registerMap(china, mapData); chart.setOption({ visualMap: { min: 0, max: 100, inRange: { color: [#e0f3f8, #4575b4] } }, series: [{ type: map, map: china, data: cityData // [{name: 北京, value: 50}, ...] }] }); });注意城市名要和地图 JSON 里的名称完全一致比如北京不能写成北京市否则地图上不会着色。这是 echarts 中国地图最常见的翻车点。6.3 接口加缓存避免重复查询每次刷新页面都重新查数据库数据量大时明显卡顿。Django 自带缓存框架给统计接口加个 5 分钟缓存from django.core.cache import cache def city_distribution(request): cache_key city_distribution result cache.get(cache_key) if result is None: data (JobInfo.objects .values(city) .annotate(countCount(id)) .order_by(-count)[:10]) result { cities: [item[city] for item in data], counts: [item[count] for item in data], } cache.set(cache_key, result, 300) # 缓存 5 分钟 return JsonResponse(result)参数说明300是缓存秒数数据不常变的话可以设长一点。开发阶段建议先不加缓存否则改了数据看不到效果容易怀疑人生。最后说个我自己的习惯每次改完采集脚本或接口先跑一遍python manage.py shell在交互环境里手动调一下 ORM 查询确认数据对了再往页面上接。这个习惯帮我省了无数次图表不对但不知道是数据问题还是前端问题的排查时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表