ScrapyJS - 如何正确等待页面加载?

时间:2016-04-04 10:30:44

标签: python scrapy scrapyjs

我正在使用ScrapyJS和Splash模拟表单提交按钮单击

def start_requests(self):
        script = """
        function main(splash)
            assert(splash:autoload("https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"))
            assert(splash:go(splash.args.url))

            local js = [[
                var $j = jQuery.noConflict();
                $j('#USER').val('frankcastle');
                $j('#password').val('punisher');
                $j('.button-oblong-orange.button-orange a').click();
            ]]

            assert(splash:runjs(js))

            local resumeJs = [[
                function main(splash) {
                    var $j = jQuery.noConflict();
                    $j(document).ready(function(){
                        splash.resume();
                    })
                }
            ]]

        assert(splash:wait_for_resume(resumeJs))

            return {
                html = splash:html()
            }
        end
        """
        splash_meta = {'splash': {'endpoint': 'execute', 'args': {'wait': 0.5, 'lua_source': script}}}

        for url in self.start_urls:
            yield scrapy.Request(url, self.after_login, meta=splash_meta)

def after_login(self, response):
        print response.body
        return

在执行splash:runjs(js)后,我使用splash:wait(5) 尝试splash:wait_for_resume来获得结果。这可能并不总是有效(网络延迟),那么有更好的方法吗?

3 个答案:

答案 0 :(得分:5)

事实证明唯一的方法是使用splash:wait()但是在循环中执行并检查某些元素的可用性(如页脚)。

def start_requests(self):
        script = """
        function main(splash)
            assert(splash:autoload("https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"))
            assert(splash:go(splash.args.url))

            local js = [[
                var $j = jQuery.noConflict();
                $j('#USER').val('frankcastle');
                $j('#password').val('punisher');
                $j('.button-oblong-orange.button-orange a').click();
                $j('body').empty() // clear body, otherwise the wait_for footer will always be true
            ]]

            assert(splash:runjs(js))

            function wait_for(splash, condition)
                while not condition() do
                    splash:wait(0.05)
                end
            end

            wait_for(splash, function()
                return splash:evaljs("document.querySelector('#footer') != null")
            end)

            return {
                html = splash:html()
            }
        end
        """
        splash_meta = {'splash': {'endpoint': 'execute', 'args': {'wait': 0.5, 'lua_source': script}}}

        for url in self.start_urls:
            yield scrapy.Request(url, self.after_login, meta=splash_meta)

答案 1 :(得分:0)

所以我还没有玩过这个(直到今天才得到Lua和Splash的一些成功尝试)。

如果您这样做:

Failed to execute 'readAsArrayBuffer' on 'FileReader': The object is already busy reading Blobs

为无限滚动页面使用类似的东西来填充列表项以响应滚动(或Page_downs)

很抱歉不熟悉Lua / Splash语法

答案 2 :(得分:0)

有一种更好的方法可以检查它,但是你需要一个有等待的循环。我们的想法是在更新页面时使用splash:on_response(response)作为回调。请注意,响应回调将被称为异步,因此主循环必须等待所有页面修改,这就是为什么我们有等待'循环(例如由@Krishnaraj提供)。

下面给出了按下按钮button_id 10次的示例,用于下载其他内容。

function main(splash)
    assert(splash:go(splash.args.url))

    function wait_for(splash, condition)
        while not condition() do
            splash:wait(0.2)
        end
    end

    local clicks = 0

    splash:on_response(function(res)
        clicks = clicks + 1

        if clicks < 10 then
            assert(splash:runjs("document.getElementById(\"button_id\").click();"))
        end
    end)

    assert(splash:runjs("document.getElementById(\"button_id\").click();"))

    wait_for(splash, function()
        return clicks >= 10
    end)

    return splash:html()
end