Python爬虫实战㉗|综合实战2,招聘网站数据分析平台
·
author: 专注Python实战,分享爬虫与数据分析干货
title: Python爬虫实战㉗|综合实战2,招聘网站数据分析平台
update: 2026-04-26
tags: Python,爬虫实战,招聘,数据分析,薪资分析,职位画像,可视化
作者:专注Python实战,分享爬虫与数据分析干货
更新时间:2026年4月
适合人群:已学完全部基础、想做完整项目的开发者
前言:找工作前,先分析市场
求职前想知道:
- 哪个城市薪资最高?
- Python岗位需要哪些技能?
- 不同经验的薪资差距多大?
爬虫采集 + Pandas分析 + 可视化 = 一份完整的招聘市场报告。
一、项目目标
1. 爬取招聘网站Python岗位数据(职位名、公司、薪资、要求等)
2. 数据清洗:统一薪资格式、提取关键词
3. 多维分析:城市/经验/学历/技能
4. 可视化:薪资分布、技能词云、城市热力图
5. 生成分析报告
二、数据爬取
2.1 爬虫设计
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
import re
class JobCrawler:
"""招聘数据爬虫"""
def __init__(self):
self.headers_list = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/119.0.0.0",
]
self.session = requests.Session()
self.jobs = []
def crawl_page(self, keyword, page):
"""爬取单页"""
url = f"https://www.example-job.com/search?keyword={keyword}&page={page}"
headers = {"User-Agent": random.choice(self.headers_list)}
try:
resp = self.session.get(url, headers=headers, timeout=15)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
items = soup.select(".job-item")
for item in items:
job = {
"职位名": self._safe_text(item.select_one(".job-title")),
"公司名": self._safe_text(item.select_one(".company-name")),
"薪资": self._safe_text(item.select_one(".salary")),
"城市": self._safe_text(item.select_one(".city")),
"经验": self._safe_text(item.select_one(".experience")),
"学历": self._safe_text(item.select_one(".education")),
"技能标签": self._safe_text(item.select_one(".tags")),
"公司规模": self._safe_text(item.select_one(".company-size")),
}
self.jobs.append(job)
except Exception as e:
print(f" 爬取失败(page={page}): {e}")
time.sleep(random.uniform(1, 3))
def _safe_text(self, element):
if element:
return element.get_text(strip=True)
return ""
def crawl(self, keyword, max_pages=10):
"""爬取多页"""
print(f"开始爬取: {keyword}")
for page in range(1, max_pages + 1):
print(f" 第{page}页...", end="")
self.crawl_page(keyword, page)
print(f" 已采集{len(self.jobs)}条")
df = pd.DataFrame(self.jobs)
print(f"\n爬取完成,共{len(df)}条数据")
return df
三、数据清洗
3.1 薪资解析
import pandas as pd
import numpy as np
import re
def parse_salary(salary_str):
"""解析薪资字符串 → 月薪范围"""
if pd.isna(salary_str) or salary_str == "":
return None, None, None
# 匹配 "15-25K" "15000-25000元/月" "15k-25k·14薪"
patterns = [
r"(\d+)[kK]\s*[-–]\s*(\d+)[kK]", # 15K-25K
r"(\d+)\s*[-–]\s*(\d+)\s*[元万]", # 15000-25000元
r"(\d+)[kK]\s*[-–]\s*(\d+)[kK][·.]\d+薪", # 15K-25K·14薪
]
for pattern in patterns:
match = re.search(pattern, salary_str)
if match:
low, high = int(match.group(1)), int(match.group(2))
# 如果是K单位,转为元
if "k" in salary_str.lower() or "K" in salary_str:
low *= 1000
high *= 1000
avg = (low + high) / 2
return low, high, avg
return None, None, None
# 应用到DataFrame
df[["薪资下限", "薪资上限", "平均薪资"]] = df["薪资"].apply(
lambda x: pd.Series(parse_salary(x))
)
# 过滤无效数据
df_valid = df.dropna(subset=["平均薪资"]).copy()
print(f"有效数据: {len(df_valid)}条")
3.2 技能标签提取
def extract_skills(tags_str):
"""提取技能标签"""
if pd.isna(tags_str):
return []
# 按常见分隔符拆分
skills = re.split(r"[,,、/|;\s]+", str(tags_str))
# 清理
skills = [s.strip() for s in skills if len(s.strip()) > 1]
return skills
df_valid["技能列表"] = df_valid["技能标签"].apply(extract_skills)
# 统计高频技能
from collections import Counter
all_skills = [s for skills in df_valid["技能列表"] for s in skills]
skill_counts = Counter(all_skills)
print("高频技能TOP20:")
for skill, count in skill_counts.most_common(20):
print(f" {skill}: {count}")
四、多维分析
4.1 城市薪资分析
# 各城市平均薪资
city_salary = df_valid.groupby("城市").agg(
岗位数=("职位名", "count"),
平均薪资=("平均薪资", "mean"),
薪资中位数=("平均薪资", "median"),
最低薪资=("薪资下限", "min"),
最高薪资=("薪资上限", "max"),
).sort_values("平均薪资", ascending=False)
print("=== 城市薪资排行 ===")
print(city_salary.round(0).head(15))
4.2 经验薪资分析
def parse_experience(exp_str):
"""解析经验要求 → 经验年限"""
if pd.isna(exp_str):
return None
match = re.search(r"(\d+)\s*[-–年]", str(exp_str))
if match:
return int(match.group(1))
if "不限" in str(exp_str) or "应届" in str(exp_str):
return 0
return None
df_valid["经验年限"] = df_valid["经验"].apply(parse_experience)
# 按经验统计
exp_salary = df_valid.groupby("经验年限").agg(
岗位数=("职位名", "count"),
平均薪资=("平均薪资", "mean"),
).sort_index()
print("\n=== 经验薪资对比 ===")
print(exp_salary.round(0))
4.3 学历薪资分析
edu_salary = df_valid.groupby("学历").agg(
岗位数=("职位名", "count"),
平均薪资=("平均薪资", "mean"),
).sort_values("平均薪资", ascending=False)
print("\n=== 学历薪资对比 ===")
print(edu_salary.round(0))
五、可视化
5.1 城市薪资排行图
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
top_cities = city_salary.head(15)
plt.figure(figsize=(10, 6))
bars = plt.barh(top_cities.index[::-1], top_cities["平均薪资"][::-1],
color=plt.cm.RdYlGn(np.linspace(0.3, 0.9, len(top_cities))))
for bar, val in zip(bars, top_cities["平均薪资"][::-1]):
plt.text(bar.get_width() + 200, bar.get_y() + bar.get_height()/2,
f"¥{val:,.0f}", va="center", fontsize=11)
plt.title("各城市Python岗位平均薪资排行", fontsize=16, fontweight="bold")
plt.xlabel("平均月薪(元)", fontsize=12)
plt.tight_layout()
plt.savefig("city_salary.png", dpi=150, bbox_inches="tight")
plt.show()
5.2 技能词云
from wordcloud import WordCloud
# 生成词云
wc = WordCloud(
font_path="C:/Windows/Fonts/simhei.ttf",
width=1000, height=600,
background_color="white",
max_words=50,
colormap="viridis",
)
wc.generate_from_frequencies(dict(skill_counts.most_common(50)))
plt.figure(figsize=(12, 7))
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.title("Python岗位高频技能词云", fontsize=16, fontweight="bold")
plt.tight_layout()
plt.savefig("skill_wordcloud.png", dpi=150, bbox_inches="tight")
plt.show()
5.3 经验-薪资箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(data=df_valid, x="经验年限", y="平均薪资", palette="Set2")
plt.title("不同经验年限的薪资分布", fontsize=16, fontweight="bold")
plt.xlabel("经验年限", fontsize=12)
plt.ylabel("月薪(元)", fontsize=12)
plt.tight_layout()
plt.savefig("exp_salary_box.png", dpi=150, bbox_inches="tight")
plt.show()
六、生成分析报告
def generate_report(df_valid, city_salary, skill_counts):
"""生成文本分析报告"""
report = f"""
╔══════════════════════════════════════════════╗
║ Python岗位招聘市场分析报告 ║
╚══════════════════════════════════════════════╝
📊 基本信息
─────────────────────────────
采集岗位数: {len(df_valid)}
涉及城市: {df_valid['城市'].nunique()}
平均月薪: ¥{df_valid['平均薪资'].mean():,.0f}
薪资中位数: ¥{df_valid['平均薪资'].median():,.0f}
薪资范围: ¥{df_valid['薪资下限'].min():,.0f} - ¥{df_valid['薪资上限'].max():,.0f}
🏙️ 薪资最高城市TOP5
─────────────────────────────
"""
for city, row in city_salary.head(5).iterrows():
report += f" {city}: ¥{row['平均薪资']:,.0f}/月 ({int(row['岗位数'])}个岗位)\n"
report += """
🔧 最热门技能TOP10
─────────────────────────────
"""
for skill, count in skill_counts.most_common(10):
pct = count / len(df_valid) * 100
report += f" {skill}: {count}次 (占比{pct:.1f}%)\n"
return report
print(generate_report(df_valid, city_salary, skill_counts))
七、知识卡
| 模块 | 说明 |
|---|---|
| JobCrawler | 招聘数据爬虫 |
| parse_salary() | 薪资字符串解析 |
| extract_skills() | 技能标签提取 |
| groupby() | 多维分组统计 |
| WordCloud | 词云可视化 |
| seaborn.boxplot | 箱线图 |
八、课后作业
必做题:
- 完成招聘数据爬虫
- 解析薪资字段并清洗
- 生成城市/经验/学历维度分析
选做题:
- 制作技能词云
- 生成完整HTML分析报告
有问题欢迎评论区留言,大家一起讨论!
标签:Python | 爬虫实战 | 招聘 | 数据分析 | 薪资分析 | 可视化 | 词云
更多推荐
所有评论(0)