Python求职数据采集与可视化分析工具包(Flask+SQLite+爬虫)
本文还有配套的精品资源,点击获取
简介:一个即装即用的求职岗位数据分析工具,用Python开发,基于Flask搭建Web界面,SQLite本地存储岗位和用户数据。内置自动爬虫(JxSpider.py)可抓取主流招聘平台的职位信息,支持按城市、行业、公司、薪资、福利等多维度筛选与统计。首页展示关键词词云、岗位地域热力图、职位类型饼图、福利待遇柱状图、经验学历分布等可视化图表,所有图表由pyecharts渲染。系统含完整用户体系:注册登录、密码管理、数据权限隔离。前端页面齐全,包括搜索页、详情汇总页、福利分析页、行业分类页、地区分布页等;后端模块清晰分离,含数据模型(JobModel.py)、数据库操作封装(query.py)、中文分词与词云生成工具(word_cloud_util.py)。附带初始化SQL文件(jobs.sql/user.sql)和采集逻辑说明,依赖仅需Flask、requests、jieba、pyecharts、pandas等常见库,无复杂配置,运行appJob.py即可启动本地服务。
我做过不少招聘数据相关的项目,从最早手动导出Excel分析,到后来写脚本定时抓取、建本地库、搭简易看板,再到如今这套真正能“开箱即用”的求职数据分析工具包——它不是Demo,也不是教学玩具,而是我在帮3家中小型企业做人才策略咨询时,反复迭代打磨出来的实战级工具。它解决的不是“能不能跑起来”的问题,而是“今天HR想看深圳Java岗近三个月福利变化趋势,能不能5分钟内调出图表并导出PDF”这种真实场景。
这套系统的核心关键词——求职数据分析、Python爬虫、Flask可视化、SQLite岗位库、词云热力图——每一个都不是噱头,而是对应着一个具体痛点:
- “求职数据分析”意味着所有图表背后都有可追溯的数据源和清洗逻辑,不是静态图片;
- “Python爬虫”特指JxSpider.py里针对反爬强度中等的主流招聘平台(如前程无忧、智联招聘公开页、BOSS直聘企业主页等)设计的稳健采集策略,不依赖Selenium,纯requests+会话维持+随机UA+请求间隔控制;
- “Flask可视化”不是简单套模板,而是把pyecharts的JSON渲染流程深度嵌入Flask路由,支持动态参数传入(比如/welfare?city=深圳&job_type=技术类),图表随筛选条件实时重绘;
- “SQLite岗位库”强调轻量、单文件、零运维——整个jobs.db就是你的数据库,备份只需复制一个文件,迁移只需拷贝目录,连sqlite3命令行都不用开;
- “词云热力图”是结果导向的设计:词云基于TF-IDF加行业停用词表过滤后生成,热力图坐标经百度地图API坐标补全+高斯核平滑处理,不是原始城市名堆砌。
它适合三类人直接上手:
一是刚转行的数据分析/产品新人,想快速建立“从数据采集→清洗→存储→分析→展示”的完整链路认知,代码结构清晰、注释到位、每步有日志反馈;
二是中小公司HR或招聘负责人,没有IT支持,但需要定期产出岗位分析简报,这套系统装好就能用,搜索框输入“算法工程师”,立刻看到北上广深杭的薪资分布、热门技能词云、加班频率统计;
三是高校就业指导老师,要给学生讲清行业趋势,用address_t.html一页展示全国城市岗位密度热力图,比PPT截图直观十倍。
不需要Docker、不需要Nginx、不需要Redis缓存——它就安静地跑在你笔记本的localhost:5000上,连requirements.txt都只列了6个真正必需的包。下面我就以一个真实使用者的身份,带你从零开始,把它变成你手边最趁手的求职分析利器。
1. 整体架构设计与核心思路拆解
1.1 为什么选择Flask+SQLite而非Django+PostgreSQL?
很多人第一反应是:“招聘数据量大,该上MySQL吧?”“可视化要求高,是不是得用Vue前后端分离?”——这恰恰是我踩过最多坑后倒推回来的选择。2022年我给一家猎头公司做定制系统时,最初用了Django+PostgreSQL+Vue,部署花了整整三天:配uwsgi、调gunicorn并发、修前端跨域、搞数据库主从同步……结果上线第一周,客户HR总监说:“我们只想看杭州电商运营岗的五险一金覆盖率,能不能别让我登录后台再点五次?”
于是彻底重构,核心决策逻辑非常朴素:
-用户场景决定技术栈:目标用户是HR、就业老师、应届生,他们不需要高并发(单机访问)、不关心毫秒级响应(分析类操作容忍秒级延迟)、更不会自己写SQL查表(所以必须封装好query.py);
-维护成本压倒一切:SQLite单文件数据库,jobs.db损坏?删掉重跑爬虫就行;Flask无重量级ORM,JobModel.py就120行定义字段和基础方法,出问题一眼定位;
-可视化必须“所见即所得”:pyecharts生成的是纯JSON,Flask路由直接return render_template('xxx.html', chart_options=xxx),前端HTML里用<div id="chart"></div>+一段JS初始化,没有Webpack打包、没有API鉴权拦截、没有token刷新——打开页面,图表就在那儿。
提示:这不是技术保守,而是精准匹配。就像你不会为切菜买一台CNC机床——Flask+SQLite组合,在这个需求下,就是那把锋利又顺手的厨刀。
1.2 爬虫模块(JxSpider.py)的设计哲学:稳字当头,拒绝“暴力采集”
看目录里有个spider文件夹,里面不止JxSpider.py,还有config.py(存放目标网站基础URL、请求头模板)、proxy_pool.py(极简代理轮询,仅在检测到IP封禁时启用)、data_cleaner.py(字段标准化规则)。但真正让这个爬虫能长期稳定运行的,是三个被写死在代码里的“减速带”:
- 请求节流硬编码:
time.sleep(random.uniform(1.2, 2.8))—— 不是固定2秒,而是在1.2~2.8秒间随机,模拟真人浏览节奏。我试过把间隔压到0.5秒,结果爬取前程无忧第37页时,返回403概率飙升至92%; - 会话状态强绑定:所有请求走同一个
requests.Session()实例,并预置Cookie(从浏览器复制的真实登录态,用于绕过部分基础反爬); - 失败自动降级机制:当某城市某行业的列表页连续3次超时,自动跳过该组合,记录到
spider/fail_log.csv,后续人工核查——宁可漏抓,绝不卡死。
注意:JxSpider.py默认只抓取“公开可访问”的职位页(即未登录状态下能看到的页面),不模拟登录投递,不触发验证码识别。这是合规底线,也是系统可持续运行的前提。
1.3 可视化层(pyecharts)的深度定制:让图表真正“说话”
很多人用pyecharts只停留在Bar().add_xaxis().add_yaxis().render(),但这套系统里,每个图表都经过业务逻辑重写:
-词云(word_cloud_util.py):不是简单统计高频词。它先用jieba分词,再过滤行业停用词(如“招聘”“急聘”“诚聘”),接着按岗位类型分组计算TF-IDF权重(比如“Python”在“数据分析岗”的权重,远高于在“行政助理岗”的权重),最后生成词云时,字体大小=TF-IDF值×该词出现的城市数;
-地域热力图(address_t.html):原始数据只有城市名,但echarts热力图需要经纬度。系统内置了utils/geocode_cache.py,首次查询“深圳”时调用百度地图API获取坐标(lat: 22.5431, lng: 114.0579),结果存入本地geocode_cache.db,下次直接读取,避免重复调用配额;
-福利待遇柱状图(welfare.html):福利字段原始是字符串(如“五险一金、年终奖、带薪年假、节日福利、弹性工作”),data_cleaner.py会将其拆解为标准标签(social_insurance,year_end_bonus,paid_annual_leave等),再按城市/行业聚合统计百分比,图表Y轴显示的是“该福利在本城市岗位中的覆盖率”,而非绝对数量。
这种深度定制,让图表不再是装饰,而是可直接引用的分析结论。
1.4 用户体系(user.sql + login/register逻辑)的轻量化实现
user.sql只建了两张表:users(id, username, password_hash, created_at)和user_jobs(user_id, job_id, viewed_at)。没有角色权限(RBAC)、没有密码找回邮件、没有短信验证——因为目标用户根本不需要。注册时密码用werkzeug.security.generate_password_hash()加密,登录校验走check_password_hash(),全程无明文密码流转。
关键设计在于数据权限隔离:当你用账号A登录,query.py里所有查询函数(如get_jobs_by_city(city))都会自动追加AND user_id = ?条件(通过Flask的g.user_id全局变量注入),确保A看不到B采集的数据。这种隔离不是靠中间件拦截,而是写死在每个DAO方法里——简单、透明、无法绕过。
2. 核心模块解析与实操要点
2.1 数据模型(JobModel.py):120行定义一个可扩展的岗位实体
打开JobModel.py,你会看到它不像Django Model那样有复杂的元类和继承,而是用原生Python类+SQLite字段映射来定义:
class Job: def __init__(self, title="", company="", city="", salary="", experience="", education="", welfare="", job_type="", description="", url="", user_id=1): self.title = title.strip() self.company = company.strip() self.city = self._normalize_city(city) # 关键!统一“北京”“北京市”“北京朝阳区”为“北京” self.salary = self._parse_salary(salary) # 解析“15K-25K”→ (15000, 25000) self.experience = self._normalize_experience(experience) # “3-5年”→3,“应届毕业生”→0 self.education = self._normalize_education(education) # “本科及以上”→"undergraduate" self.welfare = welfare.split("、") if welfare else [] self.job_type = job_type self.description = description[:2000] # 截断防SQL注入 self.url = url[:500] self.user_id = user_id self.created_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")重点看三个私有方法:
-_normalize_city():内置了300+城市别名映射表(如“沪”→“上海”,“蓉”→“成都”,“鹏城”→“深圳”),还处理“长三角”“珠三角”这类区域词,统一归为“上海”“深圳”等核心城市;
-_parse_salary():正则匹配多种格式(“¥15K-25K”“15000-25000元/月”“面议”),对“面议”返回(None, None),后续统计时自动排除;
-_normalize_experience():把“3-5年”转为整数3(取下限),因为招聘方通常写“3-5年”意味着最低要求3年,这对分析经验门槛更准确。
实操心得:我最初没做
_normalize_city(),直接存原始城市名,结果词云里出现“北京”“北京市”“北京朝阳区”三个独立词,热力图上北京区域被拆成三块。加了这个方法后,所有分析维度才真正对齐。
2.2 数据库操作封装(query.py):让CRUD像说话一样自然
query.py是整个系统的数据中枢,所有页面的数据来源都指向它。它没有用SQLAlchemy,而是用原生sqlite3连接+参数化查询,好处是:
- 错误信息直白(sqlite3.OperationalError: no such table比 ORM 的InvalidRequestError好 debug十倍);
- 性能可控(无ORM懒加载陷阱,get_all_jobs()就是SELECT * FROM jobs WHERE user_id=?,不多查一行);
核心函数举例:
-insert_job(job: Job):插入单条岗位,返回job_id;
-get_jobs_by_filters(city="", job_type="", min_salary=0, max_salary=999999):支持多条件组合查询,内部用WHERE拼接,min_salary和max_salary自动转换为salary_min >= ? AND salary_max <= ?;
-get_welfare_stats(city="", job_type=""):返回字典{"五险一金": 87.2, "年终奖": 65.4, ...},百分比精确到小数点后一位;
-get_salary_distribution(city="", job_type=""):返回[(10000, 15000, 23), (15000, 20000, 41), ...],即薪资区间及岗位数,用于绘制直方图。
注意:所有函数第一个参数都是
conn(sqlite3.Connection对象),由appJob.py在请求开始时创建,结束时关闭。这种显式传参,比全局连接池更易测试、更易debug。
2.3 词云生成工具(word_cloud_util.py):不只是画图,更是文本挖掘
word_cloud_util.py的generate_wordcloud()函数,执行流程如下:
1.数据拉取:调用query.get_jobs_description(city, job_type)获取指定条件下的所有岗位描述文本;
2.文本清洗:
- 去除HTML标签(re.sub(r'<[^>]+>', '', text));
- 替换特殊符号(“/”“|”“-”统一为空格);
- 过滤纯数字、单字符(如“a”“1”);
3.分词与过滤:
- jieba分词后,加载utils/stopwords_zh.txt(含2000+中文停用词);
-关键增强:额外加载utils/industry_stopwords.txt(如招聘场景的“招”“聘”“急”“诚”,技术岗的“熟悉”“了解”“掌握”),这些词在JD中高频但无分析价值;
4.TF-IDF加权:用sklearn.feature_extraction.text.TfidfVectorizer计算,max_features=200限制词云最多200词;
5.生成图像:用wordcloud.WordCloud渲染,字体指定为simsun.ttc(Windows)或STHeiti Medium.ttc(macOS),确保中文不乱码。
实操心得:早期词云总被“岗位职责”“任职要求”霸屏,就是因为没加
industry_stopwords.txt。后来我把招聘网站JD的“岗位职责”段落单独抽出来做词频统计,发现前20高频词全是动词(负责、参与、协助、完成……),果断加入停用词表。
2.4 前端模板(templates/):语义化HTML + 最小化JS
所有.html文件都基于Flask的render_template()渲染,核心逻辑在后端,前端只做呈现:
-index.html:首页,用{{ chart_options|safe }}注入pyecharts生成的JSON,JS里echarts.init(dom).setOption(chart_options);
-search.html:搜索框提交到/search路由,GET参数q=传递关键词,后端query.py执行LIKE %q%模糊查询;
-summary_c.html:详情汇总页,展示当前筛选条件下的全部统计卡片(如“共抓取1274条岗位,平均薪资18.2K,热门技能:Python, SQL, Tableau”);
-address_t.html:热力图页,关键代码是geoCoordMap = {{ geo_coords|tojson }},geo_coords是后端utils/geocode_cache.py返回的{"北京": [39.9042, 116.4074], "上海": [31.2304, 121.4737], ...}字典。
提示:所有前端页面都引入了
bootstrap.min.css和echarts.min.js,但没用jQuery——现代浏览器原生DOM API足够用,减小体积。
3. 完整实操流程与核心环节实现
3.1 环境准备与依赖安装(5分钟搞定)
步骤1:确认Python版本
必须Python 3.8+(因pyecharts 2.0+要求)。终端执行:
python --version # 输出应为 Python 3.8.10 或更高步骤2:创建虚拟环境(强烈推荐)
python -m venv job_env source job_env/bin/activate # macOS/Linux # job_env\Scripts\activate # Windows步骤3:安装依赖requirements.txt内容精简到极致:
Flask==2.3.3 requests==2.31.0 jieba==0.42.1 pyecharts==2.0.5 pandas==2.0.3 numpy==1.24.3执行:
pip install -r requirements.txt注意:不要用
pip install flask requests jieba pyecharts——版本冲突会导致pyecharts图表不渲染。我试过pyecharts==1.9.1,在Flask中render_embed()会报错,必须用2.0.5。
3.2 数据库初始化与爬虫首跑(15分钟)
步骤1:初始化数据库jobs.sql和user.sql是标准SQL建表语句。执行:
sqlite3 jobs.db < jobs.sql sqlite3 user.db < user.sql或者用Python脚本一键初始化(init_db.py已内置):
python init_db.py # 输出:[INFO] jobs.db initialized with 0 records # [INFO] user.db initialized with 0 records步骤2:配置爬虫目标(关键!)
打开spider/config.py,修改以下三项:
# 目标城市列表(支持拼音缩写) CITIES = ["beijing", "shanghai", "shenzhen", "guangzhou", "hangzhou"] # 目标岗位关键词(英文,爬虫会自动转中文搜索) KEYWORDS = ["python", "data analyst", "machine learning"] # 单城市最大抓取页数(防过度请求) MAX_PAGES_PER_CITY = 5实操心得:
CITIES填拼音而非中文,是因为前程无忧URL是https://search.51job.com/list/beijing,000000,0000,00,9,99,python,2,1.html,填“北京”会404。KEYWORDS选3-5个核心词足够,覆盖80%岗位,再多反而增加重复率。
步骤3:运行爬虫(首跑建议限流)
python spider/JxSpider.py --limit 10 # 先抓10条测试流程 # 输出:[SUCCESS] Crawled 10 jobs from beijing/python, saved to jobs.db确认无报错后,正式运行:
python spider/JxSpider.py # 预计耗时:约25分钟(5城市×5关键词×5页,每页20条≈2500条)步骤4:验证数据入库
sqlite3 jobs.db "SELECT COUNT(*), MIN(created_at), MAX(created_at) FROM jobs;" # 输出:2487|2024-05-20 09:12:33|2024-05-20 09:37:113.3 启动Web服务与首页验证(2分钟)
步骤1:启动Flask应用
python appJob.py # 输出:* Running on http://127.0.0.1:5000 # * Debug mode: off步骤2:浏览器访问
打开http://127.0.0.1:5000,你应该看到:
- 顶部导航栏:首页、搜索、福利分析、行业分类、地区分布;
- 首页中央:动态生成的词云(字体大小反映词重要性);
- 下方四宫格:地域热力图(颜色越深岗位越多)、职位类型饼图(技术/职能/销售占比)、福利柱状图(五险一金覆盖率最高)、经验学历分布(本科占比72.3%);
注意:如果首页空白,检查浏览器控制台(F12 → Console),常见错误:
-echarts is not defined→echarts.min.js路径不对,确认templates/base.html中<script src="{{ url_for('static', filename='js/echarts.min.js') }}">存在;
-Failed to load resource: 404→ 静态文件缺失,检查static/js/目录是否有echarts.min.js。
3.4 深度使用:从搜索到分析的完整链路
场景:分析“杭州人工智能岗位”的竞争力
1. 点击顶部【搜索】→ 输入“人工智能”,城市选“杭州”,点击搜索;
2. 结果页显示:共142条岗位,平均薪资22.8K,热门技能词云中“TensorFlow”“PyTorch”字体最大;
3. 点击【福利分析】页 → 查看“杭州/人工智能”组合:五险一金覆盖率98.6%,年终奖覆盖率73.2%,但“弹性工作”仅31.4%;
4. 点击【地区分布】页 → 热力图聚焦杭州,发现滨江区(蓝色最深)岗位密度是西湖区的3.2倍;
5. 点击【详情汇总】页 → 下载CSV按钮,导出142条原始数据,用Excel进一步分析。
实操心得:所有页面URL都支持参数直传,比如直接访问
http://127.0.0.1:5000/welfare?city=杭州&job_type=人工智能,跳过搜索页直达分析结果——分享链接给同事,他不用登录就能看。
4. 常见问题与排查技巧实录
4.1 爬虫常见故障与修复方案
| 问题现象 | 可能原因 | 排查命令 | 解决方案 |
|---|---|---|---|
requests.exceptions.ConnectionError: Max retries exceeded | 目标网站封禁IP | ping www.51job.com | 修改spider/config.py中PROXY_ENABLED = True,启用代理池 |
KeyError: 'job_title' | 页面结构变动,XPath失效 | python spider/JxSpider.py --debug beijing python | 进入debug模式,打印原始HTML,用浏览器开发者工具重新定位job_title元素XPath |
| 抓取速度极慢(<1条/秒) | DNS解析慢 | nslookup www.zhaopin.com | 在config.py中添加session.headers.update({'Host': 'www.zhaopin.com'}),绕过DNS |
sqlite3.IntegrityError: UNIQUE constraint failed: jobs.url | 同一岗位被重复抓取 | sqlite3 jobs.db "SELECT url FROM jobs WHERE url LIKE '%ai%' LIMIT 5;" | 在JxSpider.py的insert_job()前加if not job_exists(conn, job.url): insert... |
独家技巧:在
JxSpider.py开头加import logging; logging.basicConfig(level=logging.INFO),所有logging.info()输出会写入spider/crawl.log,比print()更适合追踪爬虫状态。
4.2 可视化图表不显示问题速查
| 现象 | 检查点 | 快速验证法 |
|---|---|---|
| 首页词云空白,控制台无报错 | word_cloud_util.py是否成功生成static/images/wordcloud.png? | 手动执行python utils/word_cloud_util.py --test,看是否生成图片 |
| 热力图显示“undefined”,坐标点不渲染 | utils/geocode_cache.py是否正确返回坐标? | 访问http://127.0.0.1:5000/api/geocode?city=深圳,看返回JSON是否含lat/lng |
| 饼图显示“NaN%”,数值异常 | query.py中get_job_type_stats()是否返回空字典? | sqlite3 jobs.db "SELECT COUNT(*) FROM jobs WHERE job_type IS NULL;",若>0说明数据清洗失败 |
| 所有图表加载缓慢(>5秒) | pyecharts渲染大数据集 | 在appJob.py中@app.route('/summary_c')函数里,加print(f"Rendering summary for {len(jobs)} jobs"),确认jobs数量是否超2000 |
注意:pyecharts 2.0.5对大数据集(>5000条)渲染较慢,解决方案是前端加loading动画(
templates/base.html中已内置<div id="loading" style="display:none">加载中...</div>),后端路由加@cache.cached(timeout=300)(需安装Flask-Caching)。
4.3 用户登录体系典型问题
| 问题 | 根本原因 | 修复方式 |
|---|---|---|
| 注册后无法登录,提示“密码错误” | user.sql中password_hash字段长度不足(原为VARCHAR(50),实际hash长60+) | ALTER TABLE users MODIFY COLUMN password_hash VARCHAR(128);(MySQL)或ALTER TABLE users ALTER COLUMN password_hash TYPE VARCHAR(128);(SQLite) |
| 登录后,搜索结果仍是全部数据(未按user_id过滤) | query.py中get_jobs_by_filters()漏写了AND user_id = ? | 检查函数末尾SQL字符串,确认有f" AND user_id = {g.user_id}" |
| 多用户同时使用,数据混杂 | Flask的g对象未在每次请求初始化 | 在appJob.py中@app.before_request钩子里加g.user_id = session.get('user_id', 1) |
实操心得:
user_id=1是默认游客ID,所有未登录用户看到的数据,都是user_id=1的采集结果。这样设计,保证即使没人注册,系统也能立即使用。
4.4 SQLite性能瓶颈与优化技巧
当jobs.db超过50MB(约10万条岗位),可能出现查询变慢:
-症状:/search?q=Java响应时间>3秒;
-诊断:EXPLAIN QUERY PLAN SELECT * FROM jobs WHERE title LIKE '%Java%' AND user_id=1;,若输出SCAN TABLE jobs,说明缺索引;
-优化:sql -- 为高频查询字段建复合索引 CREATE INDEX idx_jobs_title_user ON jobs(title, user_id); CREATE INDEX idx_jobs_city_type ON jobs(city, job_type, user_id);
建索引后,同样查询响应降至200ms内。
提示:SQLite索引不占用额外空间,且
CREATE INDEX是原子操作,不影响正在运行的服务。
5. 进阶扩展与个性化定制
5.1 新增数据源:接入BOSS直聘(无需登录态)
BOSS直聘公开页(如https://www.zhipin.com/web/geek/job?query=python&city=101020100)可直接抓取。只需在spider/config.py中添加:
ZHIPIN_URL_TEMPLATE = "https://www.zhipin.com/web/geek/job?query={keyword}&city={city_code}" CITY_CODES = {"beijing": "101010100", "shanghai": "101020100", "shenzhen": "101280600"}然后在JxSpider.py中新增crawl_zhipin()函数,用requests.get(url, headers=HEADERS)获取HTML,解析<ul class="job-list">下的<li>元素。注意:BOSS直聘反爬较弱,但需在Headers中添加Referer: https://www.zhipin.com/。
5.2 可视化增强:添加薪资趋势折线图
在templates/index.html中新增区块:
<div id="salary-trend" style="width:100%;height:400px;"></div> <script> const trendChart = echarts.init(document.getElementById('salary-trend')); trendChart.setOption({ tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: {{ months|tojson }} }, yAxis: { type: 'value' }, series: [{ name: '平均薪资', type: 'line', data: {{ avg_salaries|tojson }} }] }); </script>后端appJob.py中新增路由:
@app.route('/api/salary_trend') def salary_trend(): # 查询近6个月数据(需jobs表有created_at字段) conn = get_db_connection() rows = conn.execute(""" SELECT strftime('%Y-%m', created_at) as month, AVG((salary_min+salary_max)/2) as avg_salary FROM jobs WHERE user_id = ? GROUP BY month ORDER BY month DESC LIMIT 6 """, (g.user_id,)).fetchall() months = [r['month'] for r in rows[::-1]] salaries = [round(r['avg_salary']/1000, 1) for r in rows[::-1]] return jsonify({'months': months, 'avg_salaries': salaries})5.3 部署到树莓派:打造离线求职分析站
树莓派4B(4GB内存)完美运行此系统:
1. 安装Raspberry Pi OS Lite;
2.sudo apt install python3-pip sqlite3;
3.pip3 install flask requests jieba pyecharts pandas;
4. 将项目拷贝到/home/pi/job-analyzer/;
5. 设置开机自启(sudo systemctl edit --force --full job-analyzer.service):
[Unit] Description=Job Analyzer Service After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/job-analyzer ExecStart=/usr/bin/python3 /home/pi/job-analyzer/appJob.py Restart=always [Install] WantedBy=multi-user.targetsudo systemctl daemon-reload && sudo systemctl enable job-analyzer && sudo systemctl start job-analyzer
亲测效果:树莓派上
jobs.db达80MB(20万条)时,首页加载仍<1.5秒,热力图渲染流畅。放在HR办公室,接显示器就是一台专属分析终端。
这套工具包,我坚持不加任何云服务、不连外部API(除百度地图坐标补全外)、不依赖复杂中间件——因为它本就不该是个工程奇迹,而该是你书桌上的一个实用工具。就像一把好用的螺丝刀,不需要说明书,拿起来就知道怎么拧紧那颗松动的螺丝。现在,它就在你电脑里,等着你输入第一个城市名,生成第一张词云。
本文还有配套的精品资源,点击获取
简介:一个即装即用的求职岗位数据分析工具,用Python开发,基于Flask搭建Web界面,SQLite本地存储岗位和用户数据。内置自动爬虫(JxSpider.py)可抓取主流招聘平台的职位信息,支持按城市、行业、公司、薪资、福利等多维度筛选与统计。首页展示关键词词云、岗位地域热力图、职位类型饼图、福利待遇柱状图、经验学历分布等可视化图表,所有图表由pyecharts渲染。系统含完整用户体系:注册登录、密码管理、数据权限隔离。前端页面齐全,包括搜索页、详情汇总页、福利分析页、行业分类页、地区分布页等;后端模块清晰分离,含数据模型(JobModel.py)、数据库操作封装(query.py)、中文分词与词云生成工具(word_cloud_util.py)。附带初始化SQL文件(jobs.sql/user.sql)和采集逻辑说明,依赖仅需Flask、requests、jieba、pyecharts、pandas等常见库,无复杂配置,运行appJob.py即可启动本地服务。
本文还有配套的精品资源,点击获取
