拉勾网 Ajax 动态加载数据的 Python 爬虫解析

在招聘数据采集、职场趋势分析等场景中,拉勾网是重要的数据来源,但拉勾网采用 Ajax 动态加载技术渲染页面,传统的静态网页爬虫无法直接获取数据。本文将从 Ajax 动态加载原理入手,详解基于 Python 的拉勾网数据爬虫实现过程,包括请求分析、参数构造、反爬应对及数据解析存储,帮助开发者掌握动态网页爬虫的核心逻辑。

一、Ajax 动态加载原理与拉勾网数据请求分析

1.1 Ajax 动态加载核心逻辑

Ajax(Asynchronous JavaScript and XML)是一种无需刷新页面即可与服务器交换数据并更新部分网页的技术。拉勾网的职位列表、职位详情等数据均通过 Ajax 异步请求获取:前端页面加载完成后,JavaScript 会触发 HTTP 请求,服务器返回 JSON 格式的原始数据,前端再将数据渲染为可视化的网页内容。

1.2 拉勾网数据请求抓包分析

要爬取 Ajax 数据,首先需通过浏览器开发者工具分析请求参数和响应格式,步骤如下:

  1. 打开 Chrome 浏览器,访问拉勾网(https://www.lagou.com),按 F12 打开开发者工具,切换到「Network」标签;
  2. 筛选「XHR」类型(Ajax 请求专属类型),在搜索框输入目标职位(如「Python 开发」)并点击搜索;
  3. 观察 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("未爬取到任何数据")

三、反爬机制应对策略

拉勾网有严格的反爬措施,直接运行上述代码可能触发限制,需重点注意以下几点:

  • 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>保持登录状态,模拟登录流程(需处理验证码、加密参数等)。

四、注意事项与合规说明

  1. 爬取数据仅用于学习和研究,不得用于商业用途,遵守拉勾网的《用户协议》;
  2. 控制爬取频率,避免给拉勾网服务器造成压力;
  3. 若爬取过程中出现 403、500 等状态码,需立即停止爬取,排查是否触发反爬;
  4. 拉勾网的接口参数可能随版本更新变化,需定期重新抓包验证请求格式。

五、总结

本文通过解析拉勾网 Ajax 动态加载的核心逻辑,实现了基于 Python 的职位数据爬虫,核心在于准确分析 Ajax 请求的参数和响应格式,同时做好反爬应对。该思路可迁移至其他采用 Ajax 动态加载的网站(如智联招聘、BOSS 直聘等),开发者可根据实际需求扩展字段提取、数据清洗、可视化分析等功能。

相关推荐
2401_841495642 小时前
【LeetCode刷题】爬楼梯
数据结构·python·算法·leetcode·动态规划·滑动窗口·斐波那契数列
sugar椰子皮2 小时前
【DrissionPage源码-1】dp和selenium的异同
爬虫
_爱明2 小时前
查看模型参数量
人工智能·pytorch·python
m0_635647482 小时前
pyqt5打包报错:qt.qpa.plugin: Could not load the Qt platform plugin “windows“
开发语言·windows·python·qt·pyqt
人工干智能2 小时前
大模型应用中,创建OpenAI客户端的三种方式
python·llm
智算菩萨2 小时前
【Python基础】AI的“重复学习”:循环语句(for, while)的奥秘
人工智能·python·学习
代码方舟2 小时前
不仅是评分:利用 Python 解析天远借贷行为验证API 的 T0-T11 借贷时间轴数据
大数据·开发语言·python
想学后端的前端工程师2 小时前
【Java JVM虚拟机深度解析:从原理到调优】
java·jvm·python
幽影相随3 小时前
TensorBoard 快速使用指南
pytorch·python·tensorboard