页面交互

Crawl4AI 提供强大的功能,可用于与动态网页交互、处理 JavaScript 执行、等待条件以及管理多步骤流程。通过组合 js_code、wait_for 和某些 CrawlerRunConfig 参数,您可以:

  1. 点击“加载更多”按钮
  2. 填写表格并提交
  3. 等待元素或数据出现
  4. 跨多个步骤重复使用会话

下面是关于如何操作的简要概述。


1. JavaScript执行

基本执行

CrawlerRunConfig接受单个 JS 字符串或 JS 代码片段列表。示例:我们将滚动到页面底部,然后选择点击“加载更多”按钮。

import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig

async def main():
    # Single JS command
    config = CrawlerRunConfig(
        js_code="window.scrollTo(0, document.body.scrollHeight);"
    )

    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://news.ycombinator.com",  # Example site
            config=config
        )
        print("Crawled length:", len(result.cleaned_html))

    # Multiple commands
    js_commands = [
        "window.scrollTo(0, document.body.scrollHeight);",
        # 'More' link on Hacker News
        "document.querySelector('a.morelink')?.click();",  
    ]
    config = CrawlerRunConfig(js_code=js_commands)

    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://news.ycombinator.com",  # Another pass
            config=config
        )
        print("After scroll+click, length:", len(result.cleaned_html))

if __name__ == "__main__":
    asyncio.run(main())

相关的CrawlerRunConfig参数:-js_code :页面加载后运行的 JavaScript 字符串或字符串列表。 -js_only :如果设置为True在后续调用中,表示我们将继续现有会话,而无需新的完整导航。-session_id :如果您想在多次调用中保持相同的页面,请指定一个 ID。


2.等待条件

2.1 基于 CSS 的等待

有时,你只想等待特定元素出现。例如:

import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig

async def main():
    config = CrawlerRunConfig(
        # Wait for at least 30 items on Hacker News
        wait_for="css:.athing:nth-child(30)"  
    )
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://news.ycombinator.com",
            config=config
        )
        print("We have at least 30 items loaded!")
        # Rough check
        print("Total items in HTML:", result.cleaned_html.count("athing"))  

if __name__ == "__main__":
    asyncio.run(main())

关键参数:-wait_for="css:..." :告诉爬虫等待 CSS 选择器出现。

2.2 基于 JavaScript 的等待

对于更复杂的条件(例如,等待内容长度超过阈值),前缀js:

wait_condition = """() => {
    const items = document.querySelectorAll('.athing');
    return items.length > 50;  // Wait for at least 51 items
}"""

config = CrawlerRunConfig(wait_for=f"js:{wait_condition}")

幕后:Crawl4AI 持续轮询 JS 函数,直到返回true或者发生超时。


3.处理动态内容

许多现代网站需要多个步骤:滚动、点击“加载更多”或通过 JavaScript 更新。以下是一些典型的模式。

import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig

async def main():
    # Step 1: Load initial Hacker News page
    config = CrawlerRunConfig(
        wait_for="css:.athing:nth-child(30)"  # Wait for 30 items
    )
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://news.ycombinator.com",
            config=config
        )
        print("Initial items loaded.")

        # Step 2: Let's scroll and click the "More" link
        load_more_js = [
            "window.scrollTo(0, document.body.scrollHeight);",
            # The "More" link at page bottom
            "document.querySelector('a.morelink')?.click();"  
        ]

        next_page_conf = CrawlerRunConfig(
            js_code=load_more_js,
            wait_for="""js:() => {
                return document.querySelectorAll('.athing').length > 30;
            }""",
            # Mark that we do not re-navigate, but run JS in the same session:
            js_only=True,
            session_id="hn_session"
        )

        # Re-use the same crawler session
        result2 = await crawler.arun(
            url="https://news.ycombinator.com",  # same URL but continuing session
            config=next_page_conf
        )
        total_items = result2.cleaned_html.count("athing")
        print("Items after load-more:", total_items)

if __name__ == "__main__":
    asyncio.run(main())

关键参数:-session_id="hn_session" :在多次调用时保持同一页面arun().-js_only=True :我们不执行完全重新加载,只是在现有页面中应用 JS。 -wait_forjs::等待项目数量超过 30。


3.2 表单交互

如果网站有搜索或登录表单,您可以填写字段并提交js_code。例如,如果 GitHub 有一个本地搜索表单:

js_form_interaction = """
document.querySelector('#your-search').value = 'TypeScript commits';
document.querySelector('form').submit();
"""

config = CrawlerRunConfig(
    js_code=js_form_interaction,
    wait_for="css:.commit"
)
result = await crawler.arun(url="https://github.com/search", config=config)

实际上:用真实站点的表单选择器替换 ID 或类。


4. 时序控制

1.page_timeout (毫秒):整体页面加载或脚本执行的时间限制。2.delay_before_return_html (秒):等待片刻再捕获最终的 HTML。3.mean_delay &max_range :如果你打电话arun_many()对于多个 URL,这些会在每个请求之间添加一个随机暂停。

例子:

config = CrawlerRunConfig(
    page_timeout=60000,  # 60s limit
    delay_before_return_html=2.5
)

5. 多步骤交互示例

下面是一个简化的脚本,它在 GitHub 的 TypeScript 提交页面上执行多次“加载更多”操作。它每次都重复使用同一个会话来累积新的提交。代码包含相关的CrawlerRunConfig您所依赖的参数。

import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode

async def multi_page_commits():
    browser_cfg = BrowserConfig(
        headless=False,  # Visible for demonstration
        verbose=True
    )
    session_id = "github_ts_commits"

    base_wait = """js:() => {
        const commits = document.querySelectorAll('li.Box-sc-g0xbh4-0 h4');
        return commits.length > 0;
    }"""

    # Step 1: Load initial commits
    config1 = CrawlerRunConfig(
        wait_for=base_wait,
        session_id=session_id,
        cache_mode=CacheMode.BYPASS,
        # Not using js_only yet since it's our first load
    )

    async with AsyncWebCrawler(config=browser_cfg) as crawler:
        result = await crawler.arun(
            url="https://github.com/microsoft/TypeScript/commits/main",
            config=config1
        )
        print("Initial commits loaded. Count:", result.cleaned_html.count("commit"))

        # Step 2: For subsequent pages, we run JS to click 'Next Page' if it exists
        js_next_page = """
        const selector = 'a[data-testid="pagination-next-button"]';
        const button = document.querySelector(selector);
        if (button) button.click();
        """

        # Wait until new commits appear
        wait_for_more = """js:() => {
            const commits = document.querySelectorAll('li.Box-sc-g0xbh4-0 h4');
            if (!window.firstCommit && commits.length>0) {
                window.firstCommit = commits[0].textContent;
                return false;
            }
            // If top commit changes, we have new commits
            const topNow = commits[0]?.textContent.trim();
            return topNow && topNow !== window.firstCommit;
        }"""

        for page in range(2):  # let's do 2 more "Next" pages
            config_next = CrawlerRunConfig(
                session_id=session_id,
                js_code=js_next_page,
                wait_for=wait_for_more,
                js_only=True,       # We're continuing from the open tab
                cache_mode=CacheMode.BYPASS
            )
            result2 = await crawler.arun(
                url="https://github.com/microsoft/TypeScript/commits/main",
                config=config_next
            )
            print(f"Page {page+2} commits count:", result2.cleaned_html.count("commit"))

        # Optionally kill session
        await crawler.crawler_strategy.kill_session(session_id)

async def main():
    await multi_page_commits()

if __name__ == "__main__":
    asyncio.run(main())

要点:

  • :保持同一页面打开。
  • +wait_for +js_only=True :我们进行部分刷新,等待新的提交出现。
  • 确保我们每一步都能看到最新的数据。

6. 结合互动与提取

一旦动态内容加载完毕,您可以附加extraction_strategy(喜欢JsonCssExtractionStrategy或者LLMExtractionStrategy)。 例如:

from crawl4ai import JsonCssExtractionStrategy

schema = {
    "name": "Commits",
    "baseSelector": "li.Box-sc-g0xbh4-0",
    "fields": [
        {"name": "title", "selector": "h4.markdown-title", "type": "text"}
    ]
}
config = CrawlerRunConfig(
    session_id="ts_commits_session",
    js_code=js_next_page,
    wait_for=wait_for_more,
    extraction_strategy=JsonCssExtractionStrategy(schema)
)

完成后,检查result.extracted_content用于 JSON。


7.相关CrawlerRunConfig参数

以下是与交互相关的关键参数CrawlerRunConfig。有关完整列表,请参阅配置参数

  • :初始加载后运行的 JavaScript。
  • : 如果True,没有新的页面导航——只有现有会话中的 JS。
  • :CSS("css:..." ) 或 JS ("js:..." ) 表达式来等待。
  • :在各个呼叫之间重复使用同一页面。
  • :是从缓存读取/写入还是绕过。
  • :自动删除某些弹出窗口。
  • override_navigatormagic :反机器人或“类人”互动。

8. 结论

Crawl4AI 的页面交互功能可让您:

1. 执行 JavaScript 以执行滚动、点击或表单填写操作。2. 等待 CSS 或自定义 JS 条件满足后再捕获数据。3. 使用部分重新加载或持久会话处理多步骤流程(例如“加载更多”)。4. 结合结构化提取功能,实现动态网站。

使用这些工具,您可以自信地抓取现代化的交互式网页。如需高级挂钩、用户模拟或深入配置,请参阅API 参考或相关的高级文档。祝您脚本编写愉快!


9.虚拟滚动

对于使用虚拟滚动的网站(滚动时内容会被替换而不是追加,例如 Twitter 或 Instagram),Crawl4AI 提供了专用VirtualScrollConfig

from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, VirtualScrollConfig

async def crawl_twitter_timeline():
    # Configure virtual scroll for Twitter-like feeds
    virtual_config = VirtualScrollConfig(
        container_selector="[data-testid='primaryColumn']",  # Twitter's main column
        scroll_count=30,                # Scroll 30 times
        scroll_by="container_height",   # Scroll by container height each time
        wait_after_scroll=1.0          # Wait 1 second after each scroll
    )

    config = CrawlerRunConfig(
        virtual_scroll_config=virtual_config
    )

    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://twitter.com/search?q=AI",
            config=config
        )
        # result.html now contains ALL tweets from the virtual scroll

虚拟滚动 vs JavaScript 滚动

特征 虚拟卷轴 JS代码滚动
用例 滚动期间替换的内容 附加内容或简单滚动
配置 目的 使用滚动命令
自动合并 是 - 合并所有独特内容 否 - 仅捕获最终状态
最适合 Twitter、Instagram、虚拟桌子 传统页面,加载更多按钮

有关详细示例和配置选项,请参阅虚拟滚动文档


> Feedback