【问题标题】:Scrapy-Splash Waiting for Page to LoadScrapy-Splash 等待页面加载
【发布时间】:2020-01-04 02:11:41
【问题描述】:

我是 scrapy 和 splash 的新手,我需要从单页和常规网络应用中抓取数据。

但需要注意的是,我主要从内部工具和应用程序中抓取数据,因此有些需要身份验证,并且所有这些都需要至少几秒钟的加载时间才能完全加载页面。

我天真地尝试了 Python time.sleep(seconds),但没有成功。基本上,SplashRequest 和 scrapy.Request 似乎都运行并产生结果。然后,我了解了将 LUA 脚本作为这些请求的参数,并尝试了具有各种形式的 wait() 的 LUA 脚本,但看起来这些请求从未真正运行过 LUA 脚本。它立即完成,我的 HTMl 选择器没有找到我正在寻找的任何东西。

我从这里 https://github.com/scrapy-plugins/scrapy-splash 开始遵循指示,并让他们的 docker 实例在 localhost:8050 上运行并创建了一个 settings.py。

这里有经验的人知道我可能缺少什么吗?

谢谢!

spider.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy_splash import SplashRequest
import logging
import base64
import time
# from selenium import webdriver

# lua_script="""
# function main(splash)
#     splash:set_user_agent(splash.args.ua)
#     assert(splash:go(splash.args.url))
#     splash:wait(5)

#     -- requires Splash 2.3  
#     -- while not splash:select('#user-form') do
#     -- splash:wait(5)
#     -- end
#     repeat
#         splash:wait(5))
#     until( splash:select('#user-form') ~= nil )

#     return {html=splash:html()}
# end
# """

load_page_script="""
    function main(splash)
        splash:set_user_agent(splash.args.ua)
        assert(splash:go(splash.args.url))
        splash:wait(5)

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

        local result, error = splash:wait_for_resume([[
            function main(splash) {
                setTimeout(function () {
                    splash.resume();
                }, 5000);
            }
        ]])

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

        -- repeat
        -- splash:wait(5))
        -- until( splash:select('#user-form') ~= nil )

        return {html=splash:html()}
    end
"""

class HelpSpider(scrapy.Spider):
    name = "help"
    allowed_domains = ["secet_internal_url.com"]
    start_urls = ['https://secet_internal_url.com']

    # http_user = 'splash-user'
    # http_pass = 'splash-password'


    def start_requests(self):
        logger = logging.getLogger()
        login_page = 'https://secet_internal_url.com/#/auth'

        splash_args = {
            'html': 1,
            'png': 1,
            'width': 600,
            'render_all': 1,
            'lua_source': load_page_script
        }

        #splash_args = {
        #    'html': 1,
        #    'png': 1,
        #   'width': 600,
        #   'render_all': 1,
        #    'lua_source': lua_script
        #}

        yield SplashRequest(login_page, self.parse, endpoint='execute', magic_response=True, args=splash_args)

    def parse(self, response):
        # time.sleep(10)
        logger = logging.getLogger()

        html = response._body.decode("utf-8") 

        # Looking for a form with the ID 'user-form'
        form = response.css('#user-form')

        logger.info("####################")
        logger.info(form)
        logger.info("####################")

【问题讨论】:

    标签: python lua scrapy scrapy-splash


    【解决方案1】:

    我想通了!

    简答

    我的 Spider 类被错误地配置为将 splash 与 scrapy 一起使用。

    长答案

    在我的例子中,使用 scrape 运行 splash 的一部分是运行一个本地 Docker 实例,它用于将我的请求加载到其中以运行 Lua 脚本。需要注意的一个重要警告是github页面中描述的splash设置必须是spider类本身的属性,所以我将这段代码添加到我的Spider中:

    custom_settings = {
        'SPLASH_URL': 'http://localhost:8050',
        # if installed Docker Toolbox: 
        #  'SPLASH_URL': 'http://192.168.99.100:8050',
        'DOWNLOADER_MIDDLEWARES': {
            'scrapy_splash.SplashCookiesMiddleware': 723,
            'scrapy_splash.SplashMiddleware': 725,
            'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
        },
        'SPIDER_MIDDLEWARES': {
            'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
        },
        'DUPEFILTER_CLASS': 'scrapy_splash.SplashAwareDupeFilter',
    }
    

    然后我注意到我的 Lua 代码正在运行,并且 Docker 容器日志显示了交互。在使用 splash:select() 修复错误后,我的登录脚本正常工作,我的等待也是如此:

    splash:wait( seconds_to_wait )
    

    最后,我创建了一个 Lua 脚本来处理登录、重定向以及从页面收集链接和文本。我的应用程序是一个 AngularJS 应用程序,所以我无法收集链接或访问它们,除非单击。这个脚本让我可以遍历每个链接,单击它并收集内容。

    我想另一种解决方案是使用端到端测试工具,例如 Selenium/WebDriver 或 Cypress,但我更喜欢使用 scrapy 来抓取和测试工具进行测试。我想每个人都有自己的(Python 或 NodeJS 工具)。

    巧妙的技巧

    另一件对调试很有帮助的事情是,当您为 Scrapy-Splash 运行 Docker 实例时,您可以在浏览器中访问该 URL,并且有一个交互式“请求测试器”可以让您测试 Lua 脚本并查看呈现的 HTML 结果(例如,验证登录或页面访问)。对我来说,这个 url 是 http://0.0.0.0:8050,这个 URL 是在你的设置中设置的,应该配置为与你的 Docker 容器匹配。

    干杯!

    【讨论】:

    • 我已经为此苦苦挣扎了好几天。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 2017-09-13
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    相关资源
    最近更新 更多