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 箱线图

八、课后作业

必做题:

  1. 完成招聘数据爬虫
  2. 解析薪资字段并清洗
  3. 生成城市/经验/学历维度分析

选做题:

  1. 制作技能词云
  2. 生成完整HTML分析报告

有问题欢迎评论区留言,大家一起讨论!


标签:Python | 爬虫实战 | 招聘 | 数据分析 | 薪资分析 | 可视化 | 词云

更多推荐