首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >自动化网页数据抓取中的动态交互与分页处理:以地区分页数据为例

自动化网页数据抓取中的动态交互与分页处理:以地区分页数据为例

作者头像
用户8589624
发布2025-11-14 12:06:11
发布2025-11-14 12:06:11
990
举报
文章被收录于专栏:nginxnginx

自动化网页数据抓取中的动态交互与分页处理:以地区分页数据为例

在网页自动化数据抓取的过程中,很多时候我们需要面对一些复杂的场景,比如需要处理动态加载的数据、分页抓取、条件筛选和复选框等复杂的用户交互元素。本文将结合具体案例,总结如何设计一个通用的自动化抓取方案,以抓取特定地区的招采数据为例,详细探讨如何在动态网页中操作元素、处理分页、并确保数据的完整性和可靠性。

一、项目需求分析

本次任务要求实现以下几个功能点:

  1. 多地区筛选:需要按照地区列表逐个选中,然后抓取该地区的数据。
  2. 分页数据获取:由于每个地区的列表数据分页展示,需翻页抓取全部数据。
  3. 清空筛选条件:每个地区的数据获取完毕后,需清除筛选条件,以便下一次筛选。
  4. 动态数据加载:页面数据通过动态加载,因此需要等待页面完全加载后再进行操作。
  5. 防止重复点击或执行:一些操作如“点击更多按钮”只需执行一次,防止重复点击影响数据抓取。

为实现这些需求,我们主要使用了 JavaScript 的异步编程(async/await)和 DOM 操作的方法,通过等待页面元素加载、点击事件、选择框勾选等方式来获取数据。

二、主要代码结构设计

我们将整个流程划分为几个主要步骤:

  1. 定义地区列表和辅助函数:以数组形式定义地区,编写辅助函数获取下一个地区。
  2. 页面数据获取主函数 getPage:控制整个抓取过程,包括点击操作、页面数据获取、分页数据循环和筛选条件清空。
  3. 分页数据处理 retrieveCardData:处理分页逻辑,在每页抓取数据,并控制翻页按钮的更新。
  4. 异步等待 waitForElement:通过异步轮询检查元素是否加载完成,确保元素可操作性。
三、代码实现与详解

以下是整个代码的详细设计及其各个函数的功能:

1. 定义地区数组及辅助函数 getNextReg
代码语言:javascript
复制
const reg = ['河北省', '天津市', '钓鱼岛']; // 定义地区数组
let moreButtonClicked = false; // 标记“更多”按钮是否已经点击过

function getNextReg(currentRegion) {
    const currentIndex = reg.indexOf(currentRegion);
    return currentIndex < reg.length - 1 ? reg[currentIndex + 1] : null;
}

getNextReg 通过获取当前地区的索引,返回下一个地区。当到达数组末尾时返回 null,以便在 getPage 中判断是否继续抓取。

2. 主函数 getPage

该函数控制了每个地区的抓取流程,包括:点击“更多”按钮、勾选地区复选框、点击搜索按钮获取数据、循环翻页抓取当前地区全部数据,最后清除筛选条件准备进入下一个地区。

代码语言:javascript
复制
async function getPage(page, region) {
    console.log(`开始处理地区: ${region}`);

    if (!moreButtonClicked) {
        await waitForElement('div.read-more__toggle__text');
        const moreButtonContainers = document.querySelectorAll('div.read-more__toggle__text');
        for (const div of moreButtonContainers) {
            const span = div.querySelector('span.left-text');
            if (span && span.innerText.trim() === "更多") {
                span.click();
                console.log('已点击“更多”按钮');
                moreButtonClicked = true;
                await new Promise(resolve => setTimeout(resolve, 1000)); // 确保点击生效
                break;
            }
        }
    }

    // 等待页面元素加载
    await waitForElement('input[type="radio"]');
    await waitForElement('.checkbox-content-text .checkbox-name');
    await waitForElement('.card_box');

    // 设置为第二个单选项
    const radioOptions = document.querySelectorAll('input[type="radio"]');
    if (radioOptions.length >= 2 && !radioOptions[1].checked) {
        radioOptions[1].checked = true;
        radioOptions[1].dispatchEvent(new Event('change', { bubbles: true }));
    }

    // 选择地区
    let labelElement = Array.from(document.querySelectorAll('.checkbox-content-text .checkbox-name'))
        .find(el => el.textContent.includes(region));
    if (labelElement) {
        const checkbox = labelElement.closest('.cascader-menu-item').querySelector('input[type="checkbox"]');
        if (!checkbox.closest('.el-checkbox__input').classList.contains('is-checked')) {
            checkbox.click();
            console.log(`${region} 已被选中`);
            await new Promise(resolve => setTimeout(resolve, 1000));
        }
    }

    const search_btn = document.querySelector('.search-btn');
    if (search_btn) {
        search_btn.click();
        console.log('点击搜索按钮');
        await new Promise(resolve => setTimeout(resolve, 1000));
    }

    await retrieveCardData(page);

    const clearButton = document.querySelector('.filter-clear');
    if (clearButton) {
        clearButton.click();
        console.log('已点击清空按钮,重置筛选条件');
        await new Promise(resolve => setTimeout(resolve, 1000));
    }

    const nextRegion = getNextReg(region);
    if (nextRegion) {
        console.log(`准备处理下一个地区: ${nextRegion}`);
        await getPage(1, nextRegion); 
    }
}
  1. 点击“更多”按钮:在抓取开始时,先判断是否点击过“更多”按钮,避免重复操作。
  2. 等待页面元素加载:等待重要元素如复选框、单选框等加载完成,确保它们可以被操作。
  3. 勾选地区复选框:通过检索指定地区的复选框进行勾选,以切换地区筛选条件。
  4. 分页数据抓取:调用分页处理函数 retrieveCardData,完成当前地区的所有分页数据抓取。
  5. 清除筛选条件:完成当前地区的数据抓取后,点击“清空”按钮,清除筛选条件,为下一个地区做准备。
3. 分页数据抓取函数 retrieveCardData

retrieveCardData 函数的作用是从当前页开始,循环翻页直到末页为止,获取所有分页数据。

代码语言:javascript
复制
async function retrieveCardData(page) {
    while (true) {
        if (page >= 20) break;

        console.log(`当前是第 ${page} 页`);
        await waitForElement('.card_box');

        const cardItems = document.querySelectorAll('.card_box');
        const cardDataList = Array.from(cardItems).map(card => ({
            招采单位: card.querySelector('.field-item .company-name .content-wrap')?.innerText.trim() || '未找到',
            标的物: card.querySelector('.subject-matter-list-item')?.innerText.trim() || '未找到',
            发布时间: card.querySelector('.properties .value')?.innerText.trim() || '未找到',
            联系方式: card.querySelector('.field-item.field-card .value')?.innerText.trim() || '未找到'
        }));
        console.log(`当前页面的卡片数量: ${cardItems.length}`);
        console.log(cardDataList);

        const pageButtons = document.querySelectorAll('.el-pager .number');
        let needClick = Array.from(pageButtons).find(button => button.textContent.trim() === `${page + 1}`);
        if (needClick) {
            needClick.click();
            console.log(`切换到第 ${needClick.textContent.trim()} 页`);
            page += 1;
            await new Promise(resolve => setTimeout(resolve, 1000)); // 等待翻页完成
        } else {
            break;
        }
    }
}
  1. 分页数据提取:通过选择器查找 .card_box 元素,提取该页的所有招采信息。
  2. 更新页面按钮:每次翻页后重新获取分页按钮,确保页面数字和按钮状态是最新的。
  3. 分页结束条件:如果页面超过 20 页或者找不到下一页按钮,结束分页。
4. 异步等待函数 waitForElement

在动态页面抓取中,waitForElement 是确保每次页面加载完成的重要手段。它通过轮询判断元素是否加载,避免了页面未加载完成就操作的错误。

代码语言:javascript
复制
async function waitForElement(selector, timeout = 5000) {
    const startTime = Date.now();
    return new Promise((resolve, reject) => {
        const interval = setInterval(() => {
            if (document.querySelector(selector)) {
                clearInterval(interval);
                resolve();
            } else if (Date.now() - startTime > timeout) {
                clearInterval(interval);
                reject(`等待元素 ${selector} 超时`);
            }
        }, 500);
    });
}

该函数通过一个定时器每 500 毫秒检测一次指定选择器的元素是否存在,直到加载成功或超

时。这样可以保证后续代码仅在元素加载后执行,减少错误。

四、总结

在动态页面的数据抓取中,处理复杂的交互、动态数据加载和分页逻辑是一个挑战。本文以多地区招采信息抓取为例,通过 JavaScript 的异步编程、页面元素操作和分页循环处理,实现了一个较为完整的数据抓取方案。主要的技术亮点包括:

  • 异步等待元素加载:避免了数据未加载完成就开始抓取的问题。
  • 动态更新分页按钮:保证分页循环的可靠性,防止分页按钮状态过时。
  • 按需点击与选择:通过条件判断只在必要时执行特定操作,避免多余的资源浪费。

通过这些技巧,我们可以在类似的动态数据抓取项目中设计更加灵活、高效的解决方案,确保数据抓取的完整性和准确性。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自动化网页数据抓取中的动态交互与分页处理:以地区分页数据为例
    • 一、项目需求分析
    • 二、主要代码结构设计
    • 三、代码实现与详解
    • 四、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档