在招聘数据采集、职场趋势分析等场景中,拉勾网是重要的数据来源,但拉勾网采用 Ajax 动态加载技术渲染页面,传统的静态网页爬虫无法直接获取数据。本文将从 Ajax 动态加载原理入手,详解基于 Python 的拉勾网数据爬虫实现过程,包括请求分析、参数构造、反爬应对及数据解析存储,帮助开发者掌握动态网页爬虫的核心逻辑。
一、Ajax 动态加载原理与拉勾网数据请求分析
1.1 Ajax 动态加载核心逻辑
Ajax(Asynchronous JavaScript and XML)是一种无需刷新页面即可与服务器交换数据并更新部分网页的技术。拉勾网的职位列表、职位详情等数据均通过 Ajax 异步请求获取:前端页面加载完成后,JavaScript 会触发 HTTP 请求,服务器返回 JSON 格式的原始数据,前端再将数据渲染为可视化的网页内容。
1.2 拉勾网数据请求抓包分析
要爬取 Ajax 数据,首先需通过浏览器开发者工具分析请求参数和响应格式,步骤如下:
- 打开 Chrome 浏览器,访问拉勾网(https://www.lagou.com),按 F12 打开开发者工具,切换到「Network」标签;
- 筛选「XHR」类型(Ajax 请求专属类型),在搜索框输入目标职位(如「Python 开发」)并点击搜索;
- 观察 Network 面板中的请求,核心请求为
<font style="color:rgb(34, 34, 34);">positionAjax.json</font>,该请求返回职位列表的 JSON 数据。
关键请求信息梳理:
- 请求方式:POST
- 请求 URL:
<font style="color:rgb(34, 34, 34);">https://www.lagou.com/jobs/positionAjax.json</font> - 请求头:需包含
<font style="color:rgb(34, 34, 34);">User-Agent</font>、<font style="color:rgb(34, 34, 34);">Referer</font>、<font style="color:rgb(34, 34, 34);">Cookie</font>等(反爬关键) - 请求参数:
<font style="color:rgb(34, 34, 34);">first</font>(是否首次请求)、<font style="color:rgb(34, 34, 34);">pn</font>(页码)、<font style="color:rgb(34, 34, 34);">kd</font>(关键词)、<font style="color:rgb(34, 34, 34);">city</font>(城市)等
二、Python 爬虫实现核心步骤
2.1 环境准备
本次爬虫使用 Python 3.8+,核心依赖库:
<font style="color:rgb(34, 34, 34);">requests</font>:发送 HTTP 请求<font style="color:rgb(34, 34, 34);">json</font>:解析 JSON 响应数据<font style="color:rgb(34, 34, 34);">pandas</font>:数据存储为 Excel/CSV<font style="color:rgb(34, 34, 34);">time</font>:设置请求间隔,规避反爬
2.2 爬虫核心代码实现
步骤 1:构造请求头与参数
请求头需模拟真实浏览器,Cookie 可从浏览器开发者工具中复制(注意时效性),参数需动态设置页码和关键词:
python
python
import requests
import json
import pandas as pd
import time
from requests.exceptions import RequestException
# 全局配置
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
"Referer": "https://www.lagou.com/jobs/list_Python%E5%BC%80%E5%8F%91?city=%E5%8C%97%E4%BA%AC&cl=false&fromSearch=true&labelWords=&suginput=",
"Cookie": "你的Cookie(从浏览器复制)", # 替换为实际Cookie
"Host": "www.lagou.com",
"Origin": "https://www.lagou.com",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Anit-Forge-Token": "None",
"X-Anit-Forge-Code": "0"
}
# 请求参数模板
def get_params(page_num, keyword, city):
params = {
"first": "true" if page_num == 1 else "false",
"pn": page_num,
"kd": keyword,
"city": city
}
return params
步骤 2:发送 POST 请求获取数据
需处理请求异常,并设置随机延迟避免触发反爬机制:
python
运行
python
import requests
import json
import time
from requests.exceptions import RequestException
# 亿牛云代理(新增)
proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"
# 构造代理URL(包含账号密码认证)
proxy_url = f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"
proxies = {
"http": proxy_url,
"https": proxy_url
}
# 全局请求头(需保留原配置,此处仅为示例完整性展示)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
"Referer": "https://www.lagou.com/jobs/list_Python%E5%BC%80%E5%8F%91?city=%E5%8C%97%E4%BA%AC&cl=false&fromSearch=true&labelWords=&suginput=",
"Cookie": "你的Cookie(替换为实际有效Cookie)",
"Host": "www.lagou.com",
"Origin": "https://www.lagou.com",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Anit-Forge-Token": "None",
"X-Anit-Forge-Code": "0"
}
# 保留原参数构造函数(完整性展示)
def get_params(page_num, keyword, city):
params = {
"first": "true" if page_num == 1 else "false",
"pn": page_num,
"kd": keyword,
"city": city
}
return params
def get_lagou_data(page_num, keyword, city):
"""
获取单页拉勾网职位数据(整合代理信息)
:param page_num: 页码
:param keyword: 职位关键词
:param city: 城市
:return: 解析后的字典列表
"""
url = "https://www.lagou.com/jobs/positionAjax.json"
params = get_params(page_num, keyword, city)
# 转换参数为表单格式
data = f"first={params['first']}&pn={params['pn']}&kd={params['kd']}&city={params['city']}"
try:
# 设置超时时间,避免请求挂起(新增proxies参数)
response = requests.post(
url=url,
headers=headers,
data=data,
proxies=proxies, # 接入代理配置
timeout=10,
verify=False # 可选:忽略SSL证书验证(部分代理需开启)
)
# 校验响应状态
if response.status_code == 200:
result = json.loads(response.text)
# 提取职位列表数据
if result["success"] and "content" in result and "positionResult" in result["content"]:
positions = result["content"]["positionResult"]["result"]
return positions
else:
print(f"第{page_num}页请求成功但无数据:{result.get('msg', '未知错误')}")
return []
else:
print(f"第{page_num}页请求失败,状态码:{response.status_code}")
return []
except RequestException as e:
print(f"第{page_num}页请求异常:{str(e)}")
return []
finally:
# 随机延迟1-3秒,规避反爬
time.sleep(time.random() * 2 + 1)
步骤 3:多页数据爬取与字段提取
提取核心字段(职位名称、薪资、公司、工作经验、学历要求等),并循环爬取多页数据:
python
运行
python
def crawl_lagou(keyword, city, max_page=5):
"""
批量爬取拉勾网多页数据
:param keyword: 职位关键词
:param city: 城市
:param max_page: 最大爬取页码
:return: 结构化数据DataFrame
"""
all_positions = []
# 核心字段列表,可根据需求扩展
core_fields = [
"positionName", "salary", "companyShortName", "city",
"workYear", "education", "jobNature", "positionAdvantage",
"companySize", "industryField", "createTime"
]
for page in range(1, max_page + 1):
print(f"正在爬取第{page}页数据...")
positions = get_lagou_data(page, keyword, city)
if not positions:
print(f"第{page}页无数据,停止爬取")
break
# 提取核心字段,避免字段缺失报错
for pos in positions:
clean_pos = {field: pos.get(field, "未知") for field in core_fields}
all_positions.append(clean_pos)
# 转换为DataFrame,方便存储和分析
df = pd.DataFrame(all_positions)
return df
步骤 4:数据存储与结果展示
将爬取的数据存储为 Excel 文件,并打印数据概览:
python
运行
python
if __name__ == "__main__":
# 配置爬取参数
target_keyword = "Python开发"
target_city = "北京"
max_crawl_page = 5
# 执行爬取
print(f"开始爬取拉勾网【{target_city}】-{target_keyword} 职位数据...")
position_df = crawl_lagou(target_keyword, target_city, max_crawl_page)
# 数据存储
if not position_df.empty:
save_path = f"lagou_{target_city}_{target_keyword.replace('/', '_')}.xlsx"
position_df.to_excel(save_path, index=False)
print(f"数据爬取完成,共{len(position_df)}条职位信息,已保存至:{save_path}")
# 打印数据概览
print("\n数据概览:")
print(position_df[["positionName", "salary", "companyShortName", "workYear"]].head(10))
else:
print("未爬取到任何数据")
三、反爬机制应对策略
拉勾网有严格的反爬措施,直接运行上述代码可能触发限制,需重点注意以下几点:
3.1 Cookie 与请求头优化
- Cookie 需定期更新:拉勾网的 Cookie 有效期较短,建议每次爬取前从浏览器重新复制;
- 动态生成 User-Agent:可使用
<font style="color:rgb(34, 34, 34);">fake-useragent</font>库随机生成 User-Agent,避免固定标识被识别; - 补充其他请求头:如
<font style="color:rgb(34, 34, 34);">Accept</font>、<font style="color:rgb(34, 34, 34);">Accept-Encoding</font>等,完全模拟浏览器请求。
3.2 频率控制
- 避免短时间高频请求:设置 1-3 秒的随机延迟,每页爬取间隔不低于 1 秒;
- 分批次爬取:如需爬取大量数据,可分时段执行,避免单次请求超过 20 页。
3.3 账号登录(可选)
部分数据需登录后才能获取,可通过<font style="color:rgba(0, 0, 0, 0.85) !important;">requests.Session()</font>保持登录状态,模拟登录流程(需处理验证码、加密参数等)。
四、注意事项与合规说明
- 爬取数据仅用于学习和研究,不得用于商业用途,遵守拉勾网的《用户协议》;
- 控制爬取频率,避免给拉勾网服务器造成压力;
- 若爬取过程中出现 403、500 等状态码,需立即停止爬取,排查是否触发反爬;
- 拉勾网的接口参数可能随版本更新变化,需定期重新抓包验证请求格式。
五、总结
本文通过解析拉勾网 Ajax 动态加载的核心逻辑,实现了基于 Python 的职位数据爬虫,核心在于准确分析 Ajax 请求的参数和响应格式,同时做好反爬应对。该思路可迁移至其他采用 Ajax 动态加载的网站(如智联招聘、BOSS 直聘等),开发者可根据实际需求扩展字段提取、数据清洗、可视化分析等功能。