一、项目介绍

在当今竞争激烈的就业市场中,及时掌握职位信息和市场动态变得尤为重要。本文将详细介绍如何使用Python开发一个爬虫项目,自动采集BOSS直聘网站的职位数据,并对数据进行处理和分析。

1.1 项目意义

  • 帮助求职者快速获取职位信息
  • 为HR提供招聘市场分析数据
  • 辅助研究人员进行就业市场研究
  • 提供薪资水平参考数据

1.2 技术特点

  • 采用面向对象的编程方式
  • 实现了完整的反爬虫机制
  • 支持数据的自动化处理和合并
  • 提供灵活的配置选项

1.3 数据获取方式

  1. API接口爬取

    • 主要通过BOSS直聘的API接口 https://www.zhipin.com/wapi/zpgeek/search/joblist.json 获取职位列表
    • 使用requests库发送GET请求,携带必要的请求参数和headers
    • 返回数据格式为JSON,包含职位的基本信息
  2. 详情页解析

    • 通过职位ID访问详情页 https://www.zhipin.com/job_detail/{job_id}.html
    • 使用BeautifulSoup4解析HTML页面
    • 提取职位描述等详细信息

二、技术栈

2.1 核心技术

  • Python 3.x:编程语言
  • requests:网络请求库
  • BeautifulSoup4:HTML解析
  • pandas:数据处理
  • openpyxl:Excel文件操作

2.2 开发环境

  • 操作系统:支持Windows/Linux/MacOS
  • IDE:推荐PyCharm或VS Code
  • 依赖管理:pip

三、项目实现

3.1 项目结构

bosszhipin_spider/
├── README.md # 项目说明文档
├── zp_spider_main.py # 主爬虫程序
├── merge_job_excel.py # Excel数据合并工具
└── *.xlsx # 爬取的数据文件

3.2 核心功能实现

3.2.1 爬虫初始化配置

def __init__(self):
self.base_url = "https://www.zhipin.com/wapi/zpgeek/search/joblist.json"
self.headers = {
"User-Agent": "Mozilla/5.0 ...",
"Referer": "https://www.zhipin.com/",
"Cookie": "your_cookie_here"
}
self.params = {
"query": "Python高级开发工程师",
"city": "101220100",
"experience": "106",
"scale": "303,304,305",
"page": 1,
"pageSize": 30
}

3.2.2 数据采集流程

  1. 获取职位列表
def fetch_data(self, max_pages=3):
for page in range(1, max_pages + 1):
self.params['page'] = page
resp = requests.get(self.base_url,
headers=self.headers,
params=self.params)
# 处理响应数据
job_list = resp.json().get("zpData", {}).get("jobList", [])
for job in job_list:
job_id = job.get("encryptJobId")
job_desc = self.get_job_detail(job_id)
self.process_job_data(job, job_desc)
  1. 解析职位详情
def get_job_detail(self, job_id):
url = f"https://www.zhipin.com/job_detail/{job_id}.html"
resp = requests.get(url, headers=self.detail_headers)
soup = BeautifulSoup(resp.text, 'html.parser')
desc_tag = soup.select_one('.job-sec-text')
return desc_tag.text.strip() if desc_tag else ""

3.3 反爬虫策略

3.3.1 请求头处理

headers = {
"User-Agent": "Mozilla/5.0 ...",
"Referer": "https://www.zhipin.com/",
"Cookie": "your_cookie_here"
}

3.3.2 请求频率控制

import random
import time def request_with_delay(self):
time.sleep(random.uniform(1, 1.5)) # 随机延时
# 执行请求操作

3.4 数据处理

3.4.1 数据结构设计

def process_job_data(self, job, job_desc):
job_data = {
"职位": job.get("jobName"),
"公司": job.get("brandName"),
"薪资": job.get("salaryDesc"),
"地区": job.get("cityName"),
"经验": job.get("jobExperience"),
"学历": job.get("jobDegree"),
"公司规模": job.get("brandScaleName"),
"行业": job.get("brandIndustry"),
"福利标签": ",".join(job.get("welfareList", [])),
"技能标签": ",".join(job.get("skills", [])),
"职位描述": job_desc
}
self.data_list.append(job_data)

3.4.2 数据存储

def save_excel(self):
filename = f"python岗位数据_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
df = pd.DataFrame(self.data_list)
df.to_excel(filename, index=False)
print(f"数据已保存到: {filename}")

四、项目优化

4.1 性能优化

  1. 异步请求处理

    • 使用aiohttp实现异步爬取
    • 控制并发数量
    • 优化请求队列
  2. 数据处理优化

    • 使用生成器处理大数据
    • 实现增量更新
    • 优化内存使用

4.2 稳定性提升

  1. 异常处理机制
def safe_request(self, url, retries=3):
for i in range(retries):
try:
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response
except Exception as e:
print(f"请求失败 ({i+1}/{retries}): {str(e)}")
if i == retries - 1:
raise
time.sleep(2 ** i) # 指数退避
  1. 日志记录
import logging

logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
filename='spider.log'
)

五、实践经验

5.1 常见问题解决

  1. Cookie失效问题

    • 实现Cookie池
    • 定期更新Cookie
    • 多账号轮换
  2. IP限制处理

    • 使用代理IP池
    • 动态IP切换
    • 请求频率控制
  3. 数据质量保证

    • 数据完整性检查
    • 字段格式验证
    • 重复数据处理

5.2 项目扩展

  1. 数据分析功能
def analyze_salary(self):
df = pd.DataFrame(self.data_list)
salary_stats = df['薪资'].value_counts()
plt.figure(figsize=(10, 6))
salary_stats.plot(kind='bar')
plt.title('职位薪资分布')
plt.show()
  1. 可视化展示

    • 使用matplotlib绘制图表
    • 集成echarts可视化
    • 开发Web展示界面
  2. 自动化部署

    • Docker容器化
    • 定时任务调度
    • 监控告警机制

六、总结

本项目通过Python实现了BS直聘职位数据的自动化采集和处理。在开发过程中,我们重点解决了以下问题:

  1. 反爬虫机制的突破

    • 模拟浏览器行为
    • 控制请求频率
    • 使用代理IP
  2. 大量数据的高效处理

    • 异步请求优化
    • 数据结构优化
    • 存储方式优化
  3. 程序的稳定性保证

    • 完善的异常处理
    • 日志记录机制
    • 数据备份策略

七、参考资料

  1. Python官方文档
  2. Requests库文档
  3. BeautifulSoup4文档
  4. Pandas文档

八、声明

本项目仅供学习交流使用,请勿用于商业用途。使用本项目时请遵守相关法律法规,尊重网站的robots协议。对于因使用本项目造成的任何问题,本项目不承担任何责任。

九最终实现效果

十 完整代码

zp_spider_main.py

import requests
import pandas as pd
import time
import random
from bs4 import BeautifulSoup
import datetime class BossSpiderAPI:
def __init__(self):
"""
Cookie需要登录后去网页上获取
"""
self.base_url = "https://www.zhipin.com/wapi/zpgeek/search/joblist.json"
self.headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
"Referer": "https://www.zhipin.com/",
"Cookie": "lastCity=101220100; __g=-; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1744206399; HMACCOUNT=42C280446392FB0C; wt2=DlNySPpvwfKbhVut0Gr0mgKTqXmBwfqcUqRyST97FmpG1q4fuYfpOEhCiOr1dttN64ZIAMYJ2WlH238k6edxPQw~~; wbg=0; zp_at=5MyB3H6qawmfWoNUp314MzOYgaBoo-yV_45NFKxF4IU~; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1744208479; bst=V2QNMjEeP_0llgXdJtyh0QICmw7D7Rwg~~|QNMjEeP_0llgXdJtyh0QICmw7DvRwQ~~; __c=1744206399; __a=15610779.1712562134.1730179058.1744206399.26.3.12.26; __zp_stoken__=6578fRUnDnsOIwp3DiD42DRYRGxg9LUxJOzJLRTVDSUlFSUVLS0VJPSk9NTLDhl%2FDg8OSX8OcwrzCvUY2RUlFRUlDSURCJkU9wr5FSjA2w4Njw4rDkl%2FDjRjFhcOMHMKww4w3wpXDiRHCqMOIGFUvNyvDiEg9REjDssOLw6XDgcKOw4fDoMOIbcOLw6TCvT1MSMOJLkESaRxpQUxVW2sPWmFcYWVOFlNPVjpIRkpEccOML0sNHBgcGBYTDxMPExYaEQ0WEw8TDxcSDhIOPEXCnsOMWMK8w6DEosO5xKrCnk3CocK7xITCosKtZMKSwqXEgWPCtVhUwrPCrsK2wqbCrsKzXsKvw4tNwr7CpFjCqV%2FCrlFXw4hPHMKAd8OEw4p4WcK%2BVQ4ZwokPFEwVH1nDlw%3D%3D"
}
self.detail_headers = {
"User-Agent": self.headers["User-Agent"],
"Cookie": self.headers["Cookie"]
}
self.params = {
"scene": "1",
"query": "Python高级开发工程师",
"city": "101220100",# 城市:福州
"experience": "106",# 经验:3-5年
"scale": "303,304,305",# 公司规模:100-999人
"page": 1,
"pageSize": 30
}
self.data_list = [] def fetch_data(self, max_pages=3):
for page in range(1, max_pages + 1):
print(f"抓取第 {page} 页...")
self.params['page'] = page
try:
resp = requests.get(self.base_url, headers=self.headers, params=self.params)
resp.raise_for_status()
except requests.RequestException as e:
print(f"请求失败:{e}")
continue result = resp.json()
job_list = result.get("zpData", {}).get("jobList", [])
if not job_list:
print("没有更多数据了")
break for job in job_list:
job_id = job.get("encryptJobId")
job_desc = self.get_job_detail(job_id) item = {
"职位": job.get("jobName"),
"公司": job.get("brandName"),
"薪资": job.get("salaryDesc"),
"地区": job.get("cityName"),
"经验": job.get("jobExperience"),
"学历": job.get("jobDegree"),
"公司规模": job.get("brandScaleName"),
"行业": job.get("brandIndustry"),
"福利标签": ",".join(job.get("welfareList", [])),
"技能标签": ",".join(job.get("skills", [])),
"职位描述": job_desc
}
self.data_list.append(item)
time.sleep(random.uniform(1, 1.5)) def get_job_detail(self, job_id):
url = f"https://www.zhipin.com/job_detail/{job_id}.html"
try:
resp = requests.get(url, headers=self.detail_headers)
if resp.status_code != 200:
return ""
soup = BeautifulSoup(resp.text, 'html.parser')
desc_tag = soup.select_one('.job-sec-text')
return desc_tag.text.strip() if desc_tag else ""
except Exception as e:
print(f"详情页获取失败: {e}")
return "" def save_excel(self):
filename = f"python岗位数据_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
df = pd.DataFrame(self.data_list)
df.to_excel(filename, index=False)
print(f"保存成功:{filename},共 {len(df)} 条职位") def run(self):
self.fetch_data()
self.save_excel() if __name__ == "__main__":
spider = BossSpiderAPI()
spider.run()

zp_spider_main.py

import os
import pandas as pd
from openpyxl import load_workbook def merge_excelfiles(dir_path, save_path):
file_list = [os.path.join(dir_path, f) for f in os.listdir(dir_path) if f.endswith(".xlsx")] df_list = []
headers = None for file in file_list:
try:
wb = load_workbook(file, data_only=True)
for sheet_name in wb.sheetnames:
ws = wb[sheet_name]
data = list(ws.values) if not data:
print(f"️ 跳过空文件或空Sheet: {file} - {sheet_name}")
continue if headers is None:
headers = list(data[0])
data_rows = data[1:] # 去掉表头
else:
if list(data[0]) == headers:
data_rows = data[1:]
else:
data_rows = data # 有些 sheet 可能没有表头 if not data_rows:
continue df = pd.DataFrame(data_rows, columns=headers)
df_list.append(df) except Exception as e:
print(f" 读取文件失败: {file},错误: {str(e)}")
continue if df_list:
merge_data = pd.concat(df_list, axis=0)
merge_data.to_excel(save_path, index=False)
print(f" 合并完成,保存至: {save_path}")
else:
print("️ 没有数据可以合并。") # 示例路径
dir_path = "/Users/melon/Desktop/zj/odoo18/Celery/bosszhipin_spider" # 设置Excel所在目录
save_path = "merged_后端开发.xlsx" # 合并后的保存路径 merge_excelfiles(dir_path, save_path)

BS直聘职位数据采集与分析(爬虫)的更多相关文章

  1. Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗

    Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗 零.致谢 感谢BOSS直聘相对权威的招聘信息,使本人有了这次比较有意思的研究之旅. 由于爬虫持续爬取 www.zhipin.com 网 ...

  2. 基于‘BOSS直聘的招聘信息’分析企业到底需要什么样的PHP程序员

    原文地址:http://www.jtahstu.com/blog/scrapy_zhipin_php.html 基于'BOSS直聘的招聘信息'分析企业到底需要什么样的PHP程序员 标签(空格分隔): ...

  3. python分析BOSS直聘的某个招聘岗位数据

    前言 毕业找工作,在职人员换工作,离职人员找工作……不管什么人群,应聘求职,都需要先分析对应的招聘岗位,岗位需求是否和自己匹配,常见的招聘平台有:BOSS直聘.拉钩招聘.智联招聘等,我们通常的方法都是 ...

  4. 爬虫系列---scrapy post请求、框架组件和下载中间件+boss直聘爬取

    一 Post 请求 在爬虫文件中重写父类的start_requests(self)方法 父类方法源码(Request): def start_requests(self): for url in se ...

  5. 从零学习Fluter(六):Flutter仿boss直聘v1.0重构

    今天继续学习flutter,觉得这个优秀的东西,许多方面还需要完善,作为一个后来者,要多向别人学习.俗话说,“学无先后,达者为师”.今天呢,我又重新把flutter_boss这个项目代码 从头到脚看了 ...

  6. Python爬虫——Scrapy整合Selenium案例分析(BOSS直聘)

    概述 本文主要介绍scrapy架构图.组建.工作流程,以及结合selenium boss直聘爬虫案例分析 架构图 组件 Scrapy 引擎(Engine) 引擎负责控制数据流在系统中所有组件中流动,并 ...

  7. scrapy——7 scrapy-redis分布式爬虫,用药助手实战,Boss直聘实战,阿布云代理设置

    scrapy——7 什么是scrapy-redis 怎么安装scrapy-redis scrapy-redis常用配置文件 scrapy-redis键名介绍 实战-利用scrapy-redis分布式爬 ...

  8. Scrapy 爬取BOSS直聘关于Python招聘岗位

    年前的时候想看下招聘Python的岗位有多少,当时考虑目前比较流行的招聘网站就属于boss直聘,所以使用Scrapy来爬取下boss直聘的Python岗位. 1.首先我们创建一个Scrapy 工程 s ...

  9. Python的scrapy之爬取boss直聘网站

    在我们的项目中,单单分析一个51job网站的工作职位可能爬取结果不太理想,所以我又爬取了boss直聘网的工作,不过boss直聘的网站一次只能展示300个职位,所以我们一次也只能爬取300个职位. jo ...

  10. 打造IP代理池,Python爬取Boss直聘,帮你获取全国各类职业薪酬榜

    爬虫面临的问题 不再是单纯的数据一把抓 多数的网站还是请求来了,一把将所有数据塞进去返回,但现在更多的网站使用数据的异步加载,爬虫不再像之前那么方便 很多人说js异步加载与数据解析,爬虫可以做到啊,恩 ...

随机推荐

  1. Python基础-模块和包(hashlib、random、json、time、datetime和os模块)

    什么是模块和包? 模块:python中的.py文件,将一些功能按照某一种维度进行划分: 自定义.内置..第三方. 包:文件夹 里面好多个.py文件. 在讨论的时候,一般统称为:模块. 学习: 自定义模 ...

  2. Matlab转python的索引问题

    python 中numpy库可以实现类似matlab多维数组的运算.但两者在索引方式上存在一些差异.这是需要注意的.例如: % 定义一个4*4矩阵 A=1:16; A=reshape(A,[4,4]) ...

  3. [Qt基础-07 QSignalMapper]

    QSignalMapper 本文主要根据QT官方帮助文档以及日常使用,简单的介绍一下QSignalMapper的功能以及使用 文章目录 QSignalMapper 简介 使用方法 主要的函数 信号和槽 ...

  4. https证书中的subject alternative name字段作用及如何生成含该字段的证书

    背景 最近,某个运维同事找到我,说测试环境的某个域名(他也在负责维护),假设域名为test.baidu.com,以前呢,证书都是用的生产的证书,最近不让用了.问为啥呢,说不安全,现在在整改了,因为证书 ...

  5. ModuleNotFoundError: No module named '_sqlite3' when Python3

    前言 运行 python 报错:ModuleNotFoundError: No module named '_sqlite3' 解决 重新编译安装 python ./configure --enabl ...

  6. gin Http请求Body和Header的获取 request post form Query header

    gin Http请求Body和Header的获取 request post form Query header 请求参数 POST /post?id=1234&page=1 HTTP/1.1 ...

  7. linux 各种防火墙

    一.iptables防火墙1.基本操作 # 查看防火墙状态 service iptables status # 停止防火墙 service iptables stop # 启动防火墙 service ...

  8. Docker镜像介绍

    一.Docker镜像介绍 镜像是Docker的三大核心概念之一. Docker运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker会尝试先从默认的镜像仓库下载(默认使用Docker Hu ...

  9. leetcode3208. 交替组 II

    循环数组问题,指针问题 代码 比较好实现的,只需要对右端点维护,如果达到了>=k便可以被计数,循环数组可以两边循环做到 点击查看代码 class Solution { public int nu ...

  10. BUUCTF---古典密码知多少

    题目 知识 一共给出四种古典密码,分别是:猪圈密码.圣堂武士密码.标准银河字母.栅栏密码 猪圈之前有介绍 圣: 标准银河字母 更多加密方式 解题 对照解密 FGCPFLIRTUASYON 再使用栅栏 ...