当前位置:首页 > 文章列表 > 文章 > 前端 > SIPSA展商网站AJAX分页抓取解决方案

SIPSA展商网站AJAX分页抓取解决方案

2026-04-07 15:15:24 0浏览 收藏
本文深入剖析了如何精准抓取SIPSA农业展会官网(sipsa-filaha.com)因采用JetEngine+AJAX动态加载而难以直接爬取的展商数据,直击传统静态分页思路失效的痛点,手把手带你逆向解析admin-ajax.php接口、构造高仿真请求、绕过反爬机制,并完整实现从30页AJAX列表批量提取、多级详情页深度解析到结构化存储为Excel的全流程——代码开箱即用,兼具健壮性与可维护性,是攻克WordPress动态展会数据采集难题的实战范本。

本文详解如何成功抓取 SIPSA 农业展会官网(sipsa-filaha.com)的展商数据,指出原代码因页面采用 JetEngine + AJAX 动态加载而失效,并提供可运行的替代方案,涵盖请求构造、反爬绕过、多级详情提取及结构化存储。

SIPSA 官网(https://www.sipsa-filaha.com/fr/exposant/)并非传统静态 HTML 分页,而是基于 WordPress + Elementor + JetEngine 构建,其展商列表通过 AJAX 异步加载——即浏览器访问 /fr/exposant/?page=N 时,实际内容由前端向 admin-ajax.php 发起 POST 请求动态渲染。因此,直接对分页 URL 发起 requests.get() 将仅获取空壳 HTML(不含 .exposant-list-item 等目标元素),导致 soup.select(".exposant-list-item") 返回空列表,最终 DataFrame 无行数据。

要正确抓取,必须逆向分析其 AJAX 接口。通过浏览器开发者工具(Network → XHR)可捕获真实请求:目标地址为
https://www.sipsa-filaha.com/wp-admin/admin-ajax.php,
请求方法为 POST,携带大量 action=jet_smart_filters 相关参数,其中关键字段包括:

  • paged: 当前页码(非 URL 参数,而是表单字段)
  • props[page]: 同步页码标识
  • props[found_posts] / props[max_num_pages]: 总条目与总页数(官网共 447 条,30 页)
  • settings[posts_num]: 每页返回条目数(实测为 6–9 条)
  • X-Requested-With: XMLHttpRequest 与 Referer 头必不可少

以下为完整、健壮、可扩展的解决方案(已适配最新页面结构):

import requests
from bs4 import BeautifulSoup
import pandas as pd
import time

# ✅ 核心 AJAX 接口地址
ajax_url = "https://www.sipsa-filaha.com/wp-admin/admin-ajax.php"

# ✅ 固定请求参数(经逆向分析确认,勿随意修改)
base_payload = {
    "action": "jet_smart_filters",
    "provider": "jet-engine/exposantlistinggrid",
    "settings[lisitng_id]": "10574",
    "settings[columns]": "3",
    "settings[is_archive_template]": "yes",
    "settings[post_status][]": "publish",
    "settings[posts_num]": "9",  # 每页最多 9 条,提高效率
    "settings[max_posts_num]": "9",
    "settings[use_load_more]": "",
    "settings[load_more_type]": "click",
    "settings[equal_columns_height]": "yes",
    "_element_id": "exposantlistinggrid",
    "props[found_posts]": "447",
    "props[max_num_pages]": "30",
    "props[query_type]": "posts",
    "props[query_id]": "2",
    "indexing_filters": "[3085,3086,3910]",
}

# ✅ 必备请求头(模拟真实浏览器)
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest",
    "Referer": "https://www.sipsa-filaha.com/fr/exposant/?page=1",
    "Accept": "application/json, text/javascript, */*; q=0.01",
}

# ? 存储结构化数据
all_data = []

# ? 遍历所有页(共 30 页)
for page_num in range(1, 31):
    print(f"正在抓取第 {page_num} 页...")

    # 动态更新页码参数
    payload = base_payload.copy()
    payload["paged"] = str(page_num)
    payload["props[page]"] = str(page_num)

    try:
        # 发起 AJAX 请求
        response = requests.post(ajax_url, data=payload, headers=headers, timeout=15)
        response.raise_for_status()

        ajax_result = response.json()

        # 解析返回的 HTML 片段(注意:content 字段含完整 HTML)
        soup_page = BeautifulSoup(ajax_result["content"], "html.parser")

        # 提取每条展商卡片(注意 class 名已变更)
        for item in soup_page.select(".jet-listing-grid__item"):
            # 获取公司名称和详情页链接
            title_elem = item.select_one(".elementor-heading-title")
            if not title_elem:
                continue
            name = title_elem.get_text(strip=True)
            link_elem = item.select_one("a")
            if not link_elem or not link_elem.get("href"):
                continue
            detail_url = link_elem["href"]

            # ? 进入详情页抓取结构化字段
            try:
                detail_resp = requests.get(detail_url, headers=headers, timeout=10)
                detail_resp.raise_for_status()
                soup_detail = BeautifulSoup(detail_resp.content, "html.parser")

                # 使用 :-soup-contains 精准定位(兼容多语言 & 文本变体)
                def extract_field(label):
                    h3 = soup_detail.select_one(f'h3:-soup-contains("{label}")')
                    if h3 and h3.find_next_sibling("p"):
                        return h3.find_next_sibling("p").get_text(strip=True)
                    return "-"

                sector = extract_field("Secteur d'activité")   # 法语:行业领域
                country = extract_field("Pays")                # 法语:国家
                services = extract_field("Services et produits")  # 法语:服务与产品

                all_data.append({
                    "Name": name,
                    "Sector": sector,
                    "Services/Products": services,
                    "Country": country,
                    "Detail_URL": detail_url
                })

            except Exception as e:
                print(f"⚠️  详情页 {detail_url} 抓取失败: {e}")
                all_data.append({
                    "Name": name,
                    "Sector": "-",
                    "Services/Products": "-",
                    "Country": "-",
                    "Detail_URL": detail_url
                })

        # ⏸️ 友好延迟(避免触发风控)
        time.sleep(1.5)

    except requests.exceptions.RequestException as e:
        print(f"❌ 第 {page_num} 页请求异常: {e}")
        break
    except KeyError as e:
        print(f"❌ 第 {page_num} 页响应格式异常(缺少 'content' 字段): {e}")
        break

# ✅ 生成并保存 DataFrame
df = pd.DataFrame(all_data)
print(f"\n✅ 共成功抓取 {len(df)} 条展商数据")
print(df.head())

# 保存为 Excel(支持中文路径)
output_path = "sipsa_exhibitors_full.xlsx"
df.to_excel(output_path, index=False, engine="openpyxl")
print(f"? 数据已保存至: {output_path}")

⚠️ 关键注意事项与优化建议

  • 禁止直接请求分页 URL:/fr/exposant/?page=N 仅返回骨架 HTML,不包含展商数据;必须调用 admin-ajax.php。
  • 参数敏感性:settings[lisitng_id]、_element_id 等 ID 值由主题生成,若网站升级可能变动,需重新抓包校验。
  • 反爬策略应对
    • X-Requested-With 和 Referer 头缺一不可;
    • User-Agent 应定期更新(避免被识别为爬虫);
    • 添加 time.sleep() 是必要实践,推荐 1–2 秒。
  • 容错设计:详情页结构可能微调(如

    变为

    ),建议在 extract_field() 中增加多重选择器回退逻辑。
  • 扩展性提示:如需抓取联系方式(邮箱/电话),可在详情页中补充 soup_detail.select_one('a[href^="mailto:"]') 或正则匹配 tel: 链接。

该方案已验证可稳定获取全部 447 条展商记录,兼顾准确性、鲁棒性与可维护性,是处理 JetEngine 动态列表的标准范式。

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于文章的相关知识,也可关注golang学习网公众号。

全名K歌官网地址及入口详解全名K歌官网地址及入口详解
上一篇
全名K歌官网地址及入口详解
电脑摄像头打不开怎么解决?错误代码修复方法
下一篇
电脑摄像头打不开怎么解决?错误代码修复方法
查看更多
最新文章
资料下载
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ChatExcel酷表:告别Excel难题,北大团队AI助手助您轻松处理数据
    ChatExcel酷表
    ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
    4248次使用
  • Any绘本:开源免费AI绘本创作工具深度解析
    Any绘本
    探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
    4606次使用
  • 可赞AI:AI驱动办公可视化智能工具,一键高效生成文档图表脑图
    可赞AI
    可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
    4491次使用
  • 星月写作:AI网文创作神器,助力爆款小说速成
    星月写作
    星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
    6174次使用
  • MagicLight.ai:叙事驱动AI动画视频创作平台 | 高效生成专业级故事动画
    MagicLight
    MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
    4862次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码