首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我在Apify中的infiniteScroll函数不工作?

为什么我在Apify中的infiniteScroll函数不工作?
EN

Stack Overflow用户
提问于 2021-08-08 20:39:01
回答 1查看 255关注 0票数 1

我正在尝试从一个网站获取产品数据,该网站在用户向下滚动时加载产品列表。我使用Apify来做这件事。我的第一个想法是看看是否有人已经解决了这个问题,我找到了两个有用的链接:How to make the Apify Crawler to scroll full page when web page have infinite scrolling?How to scrape dynamic-loading listing and individual pages using Apify?。但是,当我尝试应用他们提到的函数时,我的Apify爬虫无法加载内容。

我使用的是一个基于基本web-scraper repository代码的网络刮板。

我试图从this link中获取数据的网站。目前我只是在学习,所以我只想能够从这一个页面中获得数据,我不需要导航到其他页面。

我使用的PageFunction如下:

代码语言:javascript
复制
async function pageFunction(context) {
    // Establishing uility constants to use throughout the code
    const { request, log, skipLinks } = context;
    const $ = context.jQuery;
    const pageTitle = $('title').first().text();
    context.log.info('Wait for website to render')
    await context.waitFor(2000)

    //Creating function to scroll the page til the bottom
    const infiniteScroll = async (maxTime) => {
        const startedAt = Date.now();
        let itemCount = $('.upcName').length;
        
        for (;;) {
            log.info(`INFINITE SCROLL --- ${itemCount} initial items loaded ---`);
            // timeout to prevent infinite loop
            if (Date.now() - startedAt > maxTime) {
                return;
            }
            
            scrollBy(0, 99999);
            await context.waitFor(1000); 
            
            const currentItemCount = $('.upcName').length;
            log.info(`INFINITE SCROLL --- ${currentItemCount} items loaded after scroll ---`);

            if (itemCount === currentItemCount) {
                return;
            }
            itemCount = currentItemCount;

        }

    };

    context.log.info('Initiating scrolling function');
    await infiniteScroll(60000);
    context.log.info(`Scraping URL: ${context.request.url}`);

    var results = []
    $(".itemGrid").each(function() {
        results.push({
            name: $(this).find('.upcName').text(),
            product_url: $(this).find('.nombreProductoDisplay').attr('href'),
            image_url: $(this).find('.lazyload').attr('data-original'),
            description: $(this).find('.block-with-text').text(),
            price: $(this).find('.upcPrice').text()
        });

    });

    return results
}

我用for(;;){...}替换了while(true){...}循环,因为我得到了一个Unexpected constant condition. (no-constant-condition)ESLint错误。

此外,我还尝试改变滚动的大小和等待时间。

尽管如此,我似乎不能让爬虫给我得到超过32个结果。

有人能给我解释一下我做错了什么吗?

#更新#我一直在做这方面的工作,无法在Apify平台上工作,所以我最初的问题仍然存在。不过,我还是设法通过在pc上运行脚本来实现滚动功能。

EN

回答 1

Stack Overflow用户

发布于 2021-08-08 23:12:01

在这种情况下,您可以在滚动后检查加载微调器的可见性,而不是尝试计算项目的数量。

通过稍微更改代码,您可以使其如下所示:

代码语言:javascript
复制
async function pageFunction(context) {
    // Establishing uility constants to use throughout the code
    const { request, log, skipLinks } = context;
    const $ = context.jQuery;
    const pageTitle = $('title').first().text();
    context.log.info('Wait for website to render')
    // wait for initial listing
    await context.waitFor('.itemGrid'); 

    context.log.info(`Scraping URL: ${context.request.url}`);

    let tries = 5; // keep track of the load spinner being invisible on the page
    const results = new Map(); // this ensures you only get unique items
   
    while (true) { // eslint-disable-line
        log.info(`INFINITE SCROLL --- ${results.size} initial items loaded ---`);
        // when the style is set to "display: none", it's hidden aka not loading any new items
        const hasLoadingSpinner = $('.itemLoader[style*="none"]').length === 0; 

        if (!hasLoadingSpinner && tries-- < 0) {
            break;
        }
        
        // scroll to page end, you can adjust the offset if it's not triggering the infinite scroll mechanism, like `document.body.scrollHeight * 0.8`
        scrollTo({ top: document.body.scrollHeight });

        $(".itemGrid").each(function() {
            const $this = $(this);

            results.set($this.find('#upcProducto').attr('value'), {
                name: $this.find('.upcName').text(),
                product_url: $this.find('.nombreProductoDisplay').attr('href'),
                image_url: $this.find('.lazyload').data('original'),
                description: $this.find('.block-with-text').text(),
                price: $this.find('.upcPrice').text()
            });
        });
      
        // because of the `tries` variable, this will effectively wait at least 5 seconds to consider it not loading anymore
        await context.waitFor(1000);       
        // scroll to top, sometimes scrolling past the end of the page does not trigger the "load more" mechanism of the page
        scrollTo({ top: 0 }); 
    }

    return [...results.values()]
}

这种方法也适用于虚拟分页,比如React virtual或Twitter results,当DOM节点不在视区中时,它们会被移除。

使用超时是非常脆弱的,根据你的刮刀工作的快/慢,你的结果会有所不同。因此,您需要一个明确的指示,表明该页面没有提供新项目。

您还可以跟踪document.body.scrollHeight,因为它会在有新项目时更改。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68704587

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档