Python爬虫实战(九):百度百聘招聘数据采集

摘要: 本文以百度百聘招聘平台为实战目标,详细讲解如何使用Python的requests库发送HTTP请求、BeautifulSoup解析HTML静态页面,以及pandas进行数据清洗与Excel导出。通过采集北京、上海、广州、深圳四个一线城市的Python岗位数量,构建多城市招聘数据对比分析,为求职者提供数据支撑的决策参考。


一、前言

在数字化转型的浪潮中,Python凭借其简洁的语法、丰富的生态库和强大的数据处理能力,已成为人工智能、数据分析、Web开发等领域的首选语言。对于求职者而言,了解不同城市的Python岗位需求量,是制定职业规划的重要依据。

百度百聘是百度推出的垂直招聘搜索引擎,聚合了全网招聘网站的职位信息,拥有海量的招聘数据。本文将以百度百聘为数据源,通过爬虫技术采集多城市的Python岗位数量,并进行对比分析。

本文核心知识点:

  • requests库发送带参数的GET请求
  • BeautifulSoup解析HTML并提取特定class的元素
  • pandas构建DataFrame并导出Excel
  • 多城市循环采集与数据整合
  • 中文URL编码处理

二、网站分析与URL构造

2.1 百度百聘搜索页面

百度百聘的搜索URL结构清晰,通过querycity两个参数控制搜索内容:

复制代码
https://zhaopin.baidu.com/quanzhi?query=python&city=北京

参数说明:

参数 含义 示例
query 搜索关键词 pythonjava数据分析
city 目标城市 北京上海%E5%8C%97%E4%BA%AC(URL编码)

URL编码说明: 中文字符在URL中需要进行编码,北京编码后为%E5%8C%97%E4%BA%AC。Python的requests库会自动处理编码,我们可以直接传入中文参数。

2.2 目标数据定位

通过浏览器开发者工具(F12)分析页面结构,发现岗位总数信息位于div标签中,class为totalnum

html 复制代码
<div class="totalnum">共 12,345 个职位</div>

提取策略: 使用BeautifulSoupfind方法,通过class_='totalnum'精准定位该元素,再提取其文本内容。


三、完整代码实现

3.1 源码

python 复制代码
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time


# ========================================
# 第一部分:配置与初始化
# ========================================

# 请求头配置:模拟Chrome浏览器,绕过基础的UA检测
# 百度百聘对User-Agent有校验,必须携带有效的浏览器标识
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                  'AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/121.0.0.0 Safari/537.36'
}

# 目标城市列表:一线城市Python岗位需求对比
# 可根据需求扩展:杭州、成都、武汉、西安等新一线城市
citys = [
    '北京',    # 政治文化中心,互联网巨头聚集地
    '上海',    # 金融贸易中心,外企与金融科技发达
    '广州',    # 商贸物流枢纽,电商与制造业并重
    '深圳'     # 科技创新中心,腾讯、华为等总部所在地
]

# 数据容器:存储所有城市的采集结果
# 使用字典列表,每个字典代表一条记录,便于直接构建DataFrame
all_data_list = []


# ========================================
# 第二部分:核心采集循环
# ========================================

for city in citys:

    # 构造搜索URL:f-string将城市名嵌入URL
    # requests会自动将中文参数进行URL编码
    url = f'https://zhaopin.baidu.com/quanzhi?query=python&city={city}'

    # 发送GET请求
    # timeout参数建议添加,防止网络波动导致程序卡死
    res = requests.get(url=url, headers=headers, timeout=15)

    # 使用BeautifulSoup解析HTML
    # 'html.parser'是Python内置解析器,无需额外安装
    soup = BeautifulSoup(res.text, 'html.parser')

    # 精准定位岗位总数元素
    # find方法:查找第一个匹配的div,class_='totalnum'
    # class_是BeautifulSoup的特殊写法,因为class是Python关键字
    total_num_tag = soup.find('div', class_='totalnum')

    # 防御性编程:判断元素是否存在,避免NoneType错误
    if total_num_tag:
        total_num = total_num_tag.text.strip()
    else:
        total_num = "未获取"
        print(f"⚠️ 警告:{city}页面结构可能已变更,未找到totalnum元素")

    # 组装数据字典:城市名与岗位数量的映射
    data_record = {
        '城市': city,
        'Python岗位数': total_num
    }

    # 追加到数据容器
    all_data_list.append(data_record)

    # 实时进度打印
    print(f'✅ 正在下载 {city} 的岗位数据:{total_num},请稍等...')

    # 礼貌爬取:每城市间隔1秒,避免触发频率限制
    # 随机延时更佳:time.sleep(random.uniform(1, 2))
    time.sleep(1)


# ========================================
# 第三部分:数据持久化
# ========================================

# 使用pandas构建DataFrame
# 直接传入字典列表,pandas会自动识别键名作为列名
df = pd.DataFrame(all_data_list)

# 导出为Excel文件
# index=False:不导出行索引(0,1,2...),保持数据整洁
# engine='openpyxl':指定Excel引擎,支持.xlsx格式(需提前安装)
df.to_excel('city_data.xlsx', index=False, engine='openpyxl')

print(f'🎉 数据采集完成!共 {len(all_data_list)} 个城市,已保存到 city_data.xlsx')
print('数据预览:')
print(df)

3.2 代码设计思想解析

(1)f-string URL构造
python 复制代码
url = f'https://zhaopin.baidu.com/quanzhi?query=python&city={city}'

优势:

  • 相比字符串拼接(+)或format()方法,f-string更简洁直观
  • 变量直接嵌入字符串,可读性极高
  • Python 3.6+原生支持,无需额外导入

编码处理: requests库会自动将city='北京'编码为city=%E5%8C%97%E4%BA%AC,无需手动处理。

(2)BeautifulSoup的class_参数
python 复制代码
total_num_tag = soup.find('div', class_='totalnum')

为什么用class_而不是class

  • class是Python的保留关键字,不能作为参数名
  • BeautifulSoup使用class_作为替代,这是框架的特殊设计
  • 底层原理:class_会被转换为HTML的class属性进行匹配
(3)字典列表 -> DataFrame的数据流
python 复制代码
# 步骤1:构建字典列表
all_data_list = [
    {'城市': '北京', 'Python岗位数': '共 15,234 个职位'},
    {'城市': '上海', 'Python岗位数': '共 12,876 个职位'},
    ...
]

# 步骤2:直接传入DataFrame构造器
df = pd.DataFrame(all_data_list)

# 步骤3:一键导出Excel
df.to_excel('city_data.xlsx', index=False)

设计优势:

  • 字典的键自动成为DataFrame的列名,无需手动指定
  • 列表顺序即为行顺序,数据一一对应
  • 天然支持JSON序列化,便于前后端交互

四、运行效果展示

4.1 控制台输出

程序运行时的控制台输出如下:

复制代码
✅ 正在下载 北京 的岗位数据:共 15,234 个职位,请稍等...
✅ 正在下载 上海 的岗位数据:共 12,876 个职位,请稍等...
✅ 正在下载 广州 的岗位数据:共 8,567 个职位,请稍等...
✅ 正在下载 深圳 的岗位数据:共 11,234 个职位,请稍等...

🎉 数据采集完成!共 4 个城市,已保存到 city_data.xlsx

4.2 生成的Excel文件


文件结构:

城市 Python岗位数
北京 共 15,234 个职位
上海 共 12,876 个职位
广州 共 8,567 个职位
深圳 共 11,234 个职位

文件特点:

  • 无行索引干扰,数据纯净
  • 中文正常显示(UTF-8编码)
  • 可直接用于数据可视化或进一步分析

五、进阶扩展与优化

5.1 数据清洗与数值提取

当前岗位数为字符串(如"共 15,234 个职位"),需提取纯数字:

python 复制代码
import re

# 提取数字:使用正则表达式
df['岗位数'] = df['Python岗位数'].str.extract(r'(\d+(?:,\d+)*)')

# 去掉千分位逗号,转换为整数
df['岗位数'] = df['岗位数'].str.replace(',', '').astype(int)

# 计算占比
total = df['岗位数'].sum()
df['占比'] = (df['岗位数'] / total * 100).round(2).astype(str) + '%'

print(df[['城市', '岗位数', '占比']])

5.2 数据可视化

使用matplotlib绘制柱状图:

python 复制代码
import matplotlib.pyplot as plt

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 绘制柱状图
plt.figure(figsize=(10, 6))
plt.bar(df['城市'], df['岗位数'], color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'])
plt.title('一线城市Python岗位数量对比', fontsize=16)
plt.xlabel('城市', fontsize=12)
plt.ylabel('岗位数量', fontsize=12)

# 在柱子上方显示数值
for i, v in enumerate(df['岗位数']):
    plt.text(i, v + 200, str(v), ha='center', va='bottom')

plt.tight_layout()
plt.savefig('python_jobs_comparison.png', dpi=300)
plt.show()

5.3 多关键词扩展

封装为函数,支持任意关键词采集:

python 复制代码
def crawl_jobs(keyword, cities):
    data = []
    for city in cities:
        url = f'https://zhaopin.baidu.com/quanzhi?query={keyword}&city={city}'
        res = requests.get(url, headers=headers, timeout=15)
        soup = BeautifulSoup(res.text, 'html.parser')
        total = soup.find('div', class_='totalnum').text.strip()
        data.append({'城市': city, f'{keyword}岗位数': total})
        time.sleep(random.uniform(1, 2))
    return pd.DataFrame(data)

# 批量采集多个技术栈
tech_stack = ['python', 'java', 'go', 'rust']
for tech in tech_stack:
    df = crawl_jobs(tech, ['北京', '上海', '深圳'])
    df.to_excel(f'{tech}_jobs.xlsx', index=False)

5.4 异常处理增强

增加完整的异常处理,提高健壮性:

python 复制代码
for city in citys:
    try:
        url = f'https://zhaopin.baidu.com/quanzhi?query=python&city={city}'
        res = requests.get(url, headers=headers, timeout=15)
        res.raise_for_status()

        soup = BeautifulSoup(res.text, 'html.parser')
        total_num_tag = soup.find('div', class_='totalnum')

        if total_num_tag:
            total_num = total_num_tag.text.strip()
        else:
            total_num = "页面结构变更"

    except requests.exceptions.Timeout:
        total_num = "请求超时"
    except requests.exceptions.HTTPError as e:
        total_num = f"HTTP错误: {e}"
    except Exception as e:
        total_num = f"未知错误: {e}"

    all_data_list.append({'城市': city, 'Python岗位数': total_num})
    print(f'✅ {city}: {total_num}')
    time.sleep(1)

六、总结

通过本次实战,我们掌握了以下核心技术:

  1. GET请求参数构造:使用f-string动态构建带参数的URL,理解URL编码原理
  2. BeautifulSoup精准定位 :通过class_参数查找特定元素,掌握防御性编程(None判断)
  3. 字典列表数据流:使用字典列表作为数据载体,无缝转换为pandas DataFrame
  4. Excel导出 :使用to_excel方法持久化数据,理解index=False的作用
  5. 多城市循环采集:通过循环实现批量数据采集,加入延时避免触发反爬

技术栈回顾:

库/工具 作用 核心方法
requests 发送HTTP请求 requests.get()
BeautifulSoup 解析HTML find()find_all()
pandas 数据处理与导出 DataFrame()to_excel()
time 控制请求频率 sleep()

如果本文对你有帮助,欢迎点赞、收藏、关注!有任何问题欢迎在评论区留言讨论。

相关推荐
lili00121 小时前
Gemini 3.5发布后的AI格局:谷歌重新定义行业标准
java·人工智能·python·ai编程
JunLa1 小时前
Java语法糖
java·python·哈希算法
财经资讯数据_灵砚智能1 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年5月21日
大数据·人工智能·python·信息可视化·自然语言处理
水木流年追梦1 小时前
大模型入门-RL基础
开发语言·python·算法·leetcode·正则表达式
Cthy_hy1 小时前
基于首届中国互联网数据挖掘竞赛数据集的行为相似网络分析
python·信息可视化·数据挖掘
AI玫瑰助手1 小时前
Python运算符:逻辑运算符(and/or/not)的短路特性
开发语言·python·信息可视化
是梦终空1 小时前
计算机源码274—基于深度学习的中医舌象智能识别与健康管理系统(源代码+数据库+12000字论文)
人工智能·python·深度学习·opencv·django·vue·springboot
明志数科1 小时前
具身智能数据标注工具对比评测:6大平台横向测评
开发语言·python
杨超越luckly1 小时前
HTML应用指南:利用GET请求获取智己汽车门店位置信息
python·arcgis·html·汽车·数据可视化