但是在增加超时值前,请先考虑将您的代码分隔为每个短小的步骤,然后一个个的提交到Splash上,例如您需要
加载100个站点,不要在脚本中写一个包含100个URL的列表,然后循环的提交它们,您可以写一段脚本加载1个页面
,然后发送100次请求到Splash。这种方法有许多好处:它使脚本更加简单,更健壮,并且能支持并行处理。
3. Splash 实例超载
当Splash实例超载的时候,也会产生504错误
Splash是以并行的方式来呈现请求的,但是并不意味着Splash会在相同的时间段内渲染所有的请求。这个并发的
数量是在启动Splash时通过参数 --slots
来设置的。当所有线程都被请求占用,新的请求任务会放入任务队列。
这个问题是一旦Splash接收到请求它就会针对这个请求开始计算时间,而不是等到Splash开始处理它的时候计算。
所以如果一个请求在内部的任务队列中待太久的话,即使他请求的站点非常快,也会造成超时。为了解决任务队列的
这个问题和提高渲染速度,您可以使用多个Splash实例,并使用能够维护自己任务队列的负载均衡器。
HAProxy 拥有所有这些特征,您可以 点击这里
查看它的配置的例子。使用负载均衡器中的共享队列也有助于提高可靠性,如果需要重启某个Splash实例,您不会丢失请求
Nginx (另外一个比较流行的负载均衡器)。仅在商业版本中提供内部的
任务队列。Nginx Plus 版
如果您想快速的入门,请参阅 Aquarium
(它是一个简单的Splash配置程序)。 或者使用像 ScrapingHub 这样的托管服务平台。
不要忘了在您的客户端代码中使用资源的超时时间(请参见 1. Slow website )。如果
Splash返回5xx的错误,那么重试几次给这个超时时间设置一个合理的值是十分有意义的事。
困难的方式
如果您希望自己在生成环境中配置,这里有几个小小的清单供您参考:
Splash应该作为守护进程,并在产品启动时候启动
如果出现错误或者段错误,必须能够重启Splash
必须减少内存的消耗
应该启动多个Splash实例,以便能够使用所有CPU的核或者多个服务器上运行
请求队列应该放到负载均衡里面,以便使Splash更加健壮 (请参阅 3. Splash 实例超载)
当然,配置监控、设置管理等等其他平常的东西也可以考虑。
为了守护Splash需要在程序启动时启动守护进程,并且在Splash崩溃时重启Splash,您可以考虑使用Docker。
从Docker 的1.2版本以后,您可以同时使用 --restart
和 -d
选项。您也可以使用一些标准的工具,像
upstart, systemd or supervisor
Docker 中 --restart
如果不与 -d
选项一起,将无法正常工作
Splash 使用未绑定的内存缓冲,因此它最终会占用所有的内存。一个解决的办法是在它占用过量内存时进行重启。
Splash中的 --maxrss
参数正是这个作用。您还可以在Docker中添加 --memory
选项。
在正式产品中固定使用同一个版本的Splash会是一个好的做法。相比于使用 scrapinghub/splash
来说
使用像 scrapinghub/splash:2.0
这样的可能会更好
如果您希望设置Splash使用的最大内存为4GB,并且加上守护进程,崩溃重启这些特性,您可以使用下面的命令
$ docker run -d -p 8050:8050 --memory=4.5G --restart=always scrapinghub/splash:3.1 --maxrss 4000
当然,您可能需要一个负载均衡。这样您可以在Splash中进行与Aquarium或者HAProxy 相关的配置
使用 Ansible 的方式
Splash 与Ansible的结合相关内容可以通过第三方项目获得:https://github.com/nabilm/ansible-splash.
页面未正常呈现
某些网站通过Splash不能正常呈现,可能的原因如下:
没有足够的等待时间,解决方案:多等待一段时间(请参阅: splash:wait ))
在私有模式下,本地存储未正常工作。这是一个常见的问题,例如一个网站基于AngularJS搭建。如果未正常加载,请关闭私有模式(请参阅 我如何关闭私有模式 )
某些时候响应体时惰性加载的,或者是在用户产生动作时候才加载(例如滚动页面)。尝试增加视口大小并等待一定时间以便让所有内容都能够呈现(请参阅 splash:set_viewport_full )。您可能也需要模拟键盘和鼠标事件(请参阅:与页面交互 )
Splash 使用的WebKit缺少某些功能。现在 Splash 使用 https://github.com/annulen/webkit ,他比QT WebKit提供的功能要多得多。我们使用的WebKit将与 annulen的WebKit一同更新
QT 或者WebKit的bug导致Splash挂起或者崩溃。通常Webkit对所有的网站都有效,但是针对某些特殊的js代码(或者其他的内容)会导致这个问题。针对这种情况,您可以在 verbose 模式中重启Splash(例如: docker run -it -p8050:8050 scrapinghub/splash -v2
) 。请注意它最终下载了哪些无关紧要的资源并使用 splash:on_request 或者 Request Filters 过滤它们
某些崩溃可以通过关闭HTML5的支持来解决(splash.html5_media_enabled 属性 或者 html5_media HTTP API 参数)。请注意在默认情况下它们是打开的
站点可能会根据UA 或者代理IP的地址来显示不同的信息。您可以使用 splash:set_user_agent 来修改默认的UA,如果您的Splash在云上运行,并且没有得到正常的返回结果。请尝试在本地重现它,以防止站点根据IP来返回内容。
站点会请求Flash,您可以通过 splash.plugins_enabled 来允许加载插件
站点请求 IndexedDB 。您可以使用 splash.indexeddb_enabled 来开启对它的支持
如果没有视频或者其他多媒体文件,请使用 html5_media 参数,或者 splash.html5_media_enabled 来打开对HTML5多媒体的支持,或者通过 splash.plugins_enabled 参数来打开对Flash的支持
网站与Splash正在使用的WebKit存在兼容性问题。一个快速的(虽然不太精确)的解决办法是尝试在Safari中打开并检查
如果您在使用Splash时出现问题,请尝试在 https://stackoverflow.com 中提问。如果您认为这是Splash的一个bug请将
问题提交到 https://github.com/scrapinghub/splash/issues
如何关闭私有模式
在Splash>=2.0的版本中,您可以关闭私有模式(默认开启)。主要有两种方法
在启动时通过 --disable-private-mode
参数,例如如果您在Docker中启动
$ sudo docker run -it -p 8050:8050 scrapinghub/splash --disable-private-mode
如果是在运行状态下,您可以使用 /execute
端点,并设置 splash.private_mode_enabled 参数为 false
请注意,如果您关闭了私有模式,那么不同请求之间可能会使用同样的浏览器信息(cookie 不受影响)。如果
您下共享环境下使用Splash,您发送请求中的相关信息可能会影响其他用户发送的请求。
有时您仍然需要关闭私有模式,WebKit的本地存储在开启私有模式时不能正常工作。并且可能无法为本地缓存提供JavaScript填充程序。
因此对于某些站点(某些基于AngularJS站)您需要关闭私有模式。
为什么Splash被首先创建
请参阅: kmike 在 reddit 上的回答
为何Splash会使用Lua做脚本而不是Python或者JavaScript
您可以在 GitHub Issue 找到答案
render.html 返回的值在浏览器上看起来不太正常
当您在浏览器中输入 http://<splash-server>:8050/render.html?url=<url>
来检查渲染结果的时候,可能
会出现样式和资源无法加载的情况。当资源是采取相对定位的时候,可能会出现这种情况,此时浏览器在加载这些
相对定位时采用的基地址是 http://<splash-server>:8050/render.html?url=<url>
而不是 url
。
这不是Splash的bug而是浏览器的正常行为。
如果您想看看这个页面经过渲染后是什么样子的,您可以使用 render.png 或者
render.jpeg 端点。如果您不想通过截屏的方式查看,但是仍然想在浏览器中查看
HTML的效果,您可以使用基地址来将相对定位的url转化为绝对定位。然后再使用浏览器加载HTML代码。
在这种情况下Splash的 baseurl 参数不能起到实质性的作用。它可以正常
呈现另一台主机上的页面,就好像在原始机器上的页面一样。比如说您可以拷贝一个HTML页面到您的机器上,但是使用
baseurl指向原来的主机。这样Splash将会使用原始的URL来解析相对的URL _[#1] 。这样您就可以正确的读取到对应的屏幕截图或者
执行JavaScript代码。
但是通过传递baseurl,您需要明确的指示Splash来使用它,但是在浏览器中做不到这点。它不会改变DOM中相对的url的
基地址。浏览器在使用这些url的时候会将地址栏中的地址作为基地址。
在DOM树中更改绝对链接与浏览器在运用基本的URL时所作的操作不同。如果您使用JS代码来查看链接的href属性,它仍然包含相对值,
即使您使用了 <base>
标签。render.html 返回DOM的快照。因此这些链接也不会被改变。
当您在浏览器中加载 render.html 得到的HTML页面时,是由您的浏览器来进行相对
地址的定位,而不是通过Splash,所以它的加载可能不太完整。
[2]这段话说的比较绕,我也不知道该怎么翻译才好,举个例子:
有这么一个站点 “http://www.example.com” 它的主页中需要加载一个js,它这个js采用相对定位的方式给出 “code.js”
如果是在这台主机上打开页面,那么在加载js的时候会去 “http://www.example.com/code.js”中查找。如果页面拷贝到本地,
在本地打开的话它会去 “http://localhost/code.js”中查找,但是如果我们设置了baseurl为 “http://www.example.com”
的话,它就能正常的从”http://www.example.com/code.js”中查找了