实战:爬取某联招聘职位需求并生成词云——从零开始的完整指南

一、项目背景:为什么我们要做这件事?

在求职季,你是否曾对着成百上千的招聘信息发呆?HR每天要筛选数百份简历,求职者要在海量岗位中找方向。如果能用技术手段快速提取岗位核心需求,无论是求职者优化简历还是企业分析人才市场,都能事半功倍。

本文将手把手教你用Python爬取某联招聘的职位需求,并通过词云可视化展示高频关键词。整个过程分为三个阶段:数据采集(爬虫)、数据处理(清洗)、数据可视化(词云),即使没有编程基础也能跟着操作。

二、工具准备:需要哪些武器?

1. 开发环境

  • Python 3.8+(推荐Anaconda集成环境)
  • 代码编辑器:VS Code/PyCharm(选你顺手的)
  • 浏览器:Chrome(用于查看网页结构)

2. 核心库安装

复制代码
pip install requests beautifulsoup4 pandas wordcloud jieba matplotlib
  • requests:发送HTTP请求
  • BeautifulSoup:解析HTML
  • pandas:数据处理
  • wordcloud:生成词云
  • jieba:中文分词
  • matplotlib:绘图展示

3. 辅助工具

  • 代理IP池(应对反爬)
  • Chrome开发者工具(按F12打开)

三、数据采集:突破反爬陷阱

1. 目标分析

打开某联招聘官网(https://www.***.com),以"Python开发"为例搜索:

  1. 观察URL结构:https://sou.***.com/?kw=Python开发&page=1
  2. 翻页规律:每页参数page递增
  3. 职位列表容器:通过开发者工具找到.job-list ul li

2. 基础爬虫代码

python 复制代码
import requests
from bs4 import BeautifulSoup

def get_job_list(keyword, page):
    url = f"https://sou.***.com/?kw={keyword}&page={page}"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    try:
        response = requests.get(url, headers=headers, timeout=10)
        if response.status_code == 200:
            soup = BeautifulSoup(response.text, 'html.parser')
            jobs = []
            for li in soup.select('.job-list ul li'):
                title = li.select_one('.job-title').text.strip()
                company = li.select_one('.company-name').text.strip()
                salary = li.select_one('.salary').text.strip() if li.select_one('.salary') else "面议"
                requirement = li.select_one('.job-requirements').text.strip() if li.select_one('.job-requirements') else ""
                jobs.append({
                    'title': title,
                    'company': company,
                    'salary': salary,
                    'requirement': requirement
                })
            return jobs
        else:
            print(f"请求失败,状态码:{response.status_code}")
            return []
    except Exception as e:
        print(f"发生错误:{e}")
        return []

3. 反爬策略升级

问题1:直接请求返回403

  • 解决方案:添加更多请求头字段

    makefile 复制代码
    headers = {
        "User-Agent": "...",
        "Referer": "https://www.***.com/",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cookie": "你的浏览器cookie(可选)"
    }

问题2:频繁请求被封IP

  • 解决方案:使用代理IP池

    ini 复制代码
    import random
    
    proxies = [
        {"http": "http://123.123.123.123:8080"},
        {"http": "http://124.124.124.124:8081"}
    ]
    
    response = requests.get(url, headers=headers, proxies=random.choice(proxies), timeout=10)

进阶技巧

  • 使用time.sleep(random.uniform(1,3))添加随机延迟
  • 购买付费代理服务(如快代理、芝麻代理)
  • 分布式爬取(多线程/多进程)

4. 完整采集流程

ini 复制代码
def crawl_all_pages(keyword, max_pages=5):
    all_jobs = []
    for page in range(1, max_pages+1):
        print(f"正在爬取第{page}页...")
        jobs = get_job_list(keyword, page)
        if not jobs:
            break
        all_jobs.extend(jobs)
        time.sleep(2)  # 礼貌性延迟
    return all_jobs

# 执行爬取
jobs_data = crawl_all_pages("Python开发", 3)

四、数据处理:提取核心需求

1. 数据清洗

ini 复制代码
import pandas as pd

df = pd.DataFrame(jobs_data)
# 去除空值
df = df.dropna(subset=['requirement'])
# 保存原始数据(可选)
df.to_csv('zhaopin_raw.csv', index=False, encoding='utf_8_sig')

2. 需求文本提取

观察发现,职位描述通常包含:

  • 岗位职责(以"岗位职责:"开头)

  • 任职要求(以"任职要求:"开头)

  • 其他信息(公司福利等)

    scss 复制代码
    def extract_requirements(text):
        if not text:
            return ""
        # 简单分割(实际可能需要更复杂的正则)
        parts = text.split('任职要求:')
        if len(parts) > 1:
            return parts[1].split('职位福利:')[0].strip()
        else:
            return text.split('岗位职责:')[-1].split('职位福利:')[0].strip()
    
    df['clean_require'] = df['requirement'].apply(extract_requirements)

3. 合并所有需求文本

bash 复制代码
all_requirements = ' '.join(df['clean_require'].tolist())

五、词云生成:可视化核心技能

1. 中文分词处理

csharp 复制代码
import jieba

# 添加自定义词典(可选)
jieba.load_userdict("tech_terms.txt")  # 可自行准备技术术语词典

# 分词并过滤停用词
stopwords = set()
with open('stopwords.txt', 'r', encoding='utf-8') as f:  # 停用词表
    for line in f:
        stopwords.add(line.strip())

words = [word for word in jieba.cut(all_requirements) 
         if len(word) > 1 and word not in stopwords and not word.isspace()]
word_str = ' '.join(words)

2. 生成词云

ini 复制代码
from wordcloud import WordCloud
import matplotlib.pyplot as plt

# 设置词云参数
wc = WordCloud(
    font_path='simhei.ttf',  # 中文字体文件路径
    background_color='white',
    width=800,
    height=600,
    max_words=100,
    max_font_size=100
)

# 生成词云
wc.generate(word_str)

# 显示词云
plt.figure(figsize=(10, 8))
plt.imshow(wc, interpolation='bilinear')
plt.axis('off')
plt.savefig('zhaopin_wordcloud.png', dpi=300, bbox_inches='tight')
plt.show()

3. 结果优化技巧

  • 调整形状:使用图片蒙版(需Pillow库)

    python 复制代码
    from PIL import Image
    import numpy as np
    
    mask = np.array(Image.open("python_logo.png"))
    wc = WordCloud(mask=mask, ...)
  • 颜色定制 :通过colormap参数选择matplotlib配色方案

  • 词频统计 :用collections.Counter查看高频词

六、完整代码整合

ini 复制代码
import requests
from bs4 import BeautifulSoup
import pandas as pd
import jieba
from wordcloud import WordCloud
import matplotlib.pyplot as plt
import time
import random

# 1. 数据采集
def get_job_list(keyword, page):
    url = f"https://sou.***.com/?kw={keyword}&page={page}"
    headers = {
        "User-Agent": "Mozilla/5.0...",
        "Referer": "https://www.***.com/"
    }
    try:
        response = requests.get(url, headers=headers, timeout=10)
        if response.status_code == 200:
            soup = BeautifulSoup(response.text, 'html.parser')
            jobs = []
            for li in soup.select('.job-list ul li'):
                # 解析逻辑同上...
            return jobs
        return []
    except:
        return []

# 2. 数据处理
def process_data(jobs_data):
    df = pd.DataFrame(jobs_data)
    df = df.dropna(subset=['requirement'])
    
    def extract_req(text):
        # 提取逻辑同上...
        pass
    
    df['clean_require'] = df['requirement'].apply(extract_req)
    all_text = ' '.join(df['clean_require'].tolist())
    return all_text

# 3. 生成词云
def generate_wordcloud(text):
    stopwords = set(['可以', '能够', '具有', '等'])  # 示例停用词
    words = [word for word in jieba.cut(text) 
             if len(word) > 1 and word not in stopwords]
    
    wc = WordCloud(
        font_path='simhei.ttf',
        width=800,
        height=600
    ).generate(' '.join(words))
    
    plt.figure(figsize=(10, 8))
    plt.imshow(wc)
    plt.axis('off')
    plt.savefig('output.png')
    plt.show()

# 主流程
if __name__ == "__main__":
    keyword = "Python开发"
    jobs = []
    for page in range(1, 4):
        jobs.extend(get_job_list(keyword, page))
        time.sleep(2)
    
    text = process_data(jobs)
    generate_wordcloud(text)

七、常见问题Q&A

Q1:被网站封IP怎么办?

A:立即启用备用代理池,建议使用住宅代理(如站大爷IP代理),配合每请求更换IP策略。更稳妥的方式是购买付费代理服务,这类代理通常有更高的匿名度和稳定性。

Q2:如何获取更精准的职位描述?

A:某联招聘的HTML结构可能变化,建议:

  1. 按F12打开开发者工具
  2. 在Elements面板搜索关键词如"职责"
  3. 更新CSS选择器路径(如.job-description > p

Q3:词云中出现无关词汇怎么过滤?

A:三步解决:

  1. 扩充停用词表(添加"工作"、"经验"等常见词)
  2. 在分词后添加词性过滤(保留名词/动词)
  3. 设置min_font_size参数过滤低频词

Q4:如何爬取其他招聘网站?

A:核心流程相同,需注意:

  1. 分析目标网站的URL结构
  2. 调整CSS选择器匹配新页面
  3. 可能需要处理验证码(建议使用打码平台)

Q5:代码运行报错怎么办?

A:按这个顺序排查:

  1. 检查网络连接是否正常
  2. 确认目标网站是否改版(更新选择器)
  3. 查看完整错误信息(用try-except捕获异常)
  4. 在GitHub搜索类似错误解决方案

八、进阶建议

  1. 定时任务 :用schedule库实现每天自动爬取
  2. 数据存储:将结果存入MySQL/MongoDB
  3. 分析扩展:统计不同城市的技能需求差异
  4. 部署上线:用Flask搭建简单数据看板

通过这个项目,你不仅掌握了网络爬虫和数据分析的基本技能,更重要的是建立了从数据采集到价值输出的完整思维链条。下次面对海量招聘信息时,你就可以用代码快速提炼关键信息,让技术真正服务于实际需求。

相关推荐
deephub42 分钟前
从零开始:用Python和Gemini 3四步搭建你自己的AI Agent
人工智能·python·大语言模型·agent
咕白m6251 小时前
Python 实现 PDF 页面旋转
python
c***87192 小时前
Flask:后端框架使用
后端·python·flask
Q_Q5110082853 小时前
python+django/flask的情绪宣泄系统
spring boot·python·pycharm·django·flask·node.js·php
撸码猿3 小时前
《Python AI入门》第9章 让机器读懂文字——NLP基础与情感分析实战
人工智能·python·自然语言处理
二川bro3 小时前
多模态AI开发:Python实现跨模态学习
人工智能·python·学习
2301_764441333 小时前
Python构建输入法应用
开发语言·python·算法
love530love3 小时前
【笔记】ComfUI RIFEInterpolation 节点缺失问题(cupy CUDA 安装)解决方案
人工智能·windows·笔记·python·插件·comfyui
青瓷程序设计3 小时前
昆虫识别系统【最新版】Python+TensorFlow+Vue3+Django+人工智能+深度学习+卷积神经网络算法
人工智能·python·深度学习