def __call__(self, *args): args = self.lua.lua2python(args) args_text = json.dumps(args, ensure_ascii=False, encoding="utf8")[1:-1] func_text = json.dumps([self.source], ensure_ascii=False, encoding='utf8')[1:-1] wrapper_script = """ (function(func_text){ try{ var func = eval("(" + func_text + ")"); return { result: func(%(args)s), error: false, } } catch(e){ return { error: true, error_repr: e.toString(), } } })(%(func_text)s) """ % {"func_text": func_text, "args": args_text} # print(wrapper_script) res = self.tab.evaljs(wrapper_script) if not isinstance(res, dict): raise ScriptError("[lua] unknown error during JS function call: %r; %r" % (res, wrapper_script)) if res["error"]: raise ScriptError("[lua] error during JS function call: %r" % (res.get("error_repr", "<unknown error>"),)) return res.get("result")
def set_result_header(self, name, value): if not all([isinstance(h, basestring) for h in [name, value]]): raise ScriptError( "splash:set_result_header() arguments must be strings") try: name = name.decode('utf-8').encode('ascii') value = value.decode('utf-8').encode('ascii') except UnicodeEncodeError: raise ScriptError( "splash:set_result_header() arguments must be ascii") header = (name, value) self._result_headers.append(header)
def start(self, lua_source, sandboxed, lua_package_path, lua_sandbox_allowed_modules): self.log(lua_source) self.sandboxed = sandboxed self.lua = SplashLuaRuntime( sandboxed=sandboxed, lua_package_path=lua_package_path, lua_sandbox_allowed_modules=lua_sandbox_allowed_modules) self.splash = Splash(self.lua, self.tab, self.render_options) self.runner = SplashScriptRunner( lua=self.lua, splash=self.splash, log=self.log, sandboxed=sandboxed, ) try: main_coro = self.get_main(lua_source) except (ValueError, lupa.LuaSyntaxError, lupa.LuaError) as e: raise ScriptError("lua_source: " + repr(e)) self.runner.start( main_coro=main_coro, return_result=self.return_result, return_error=self.return_error, )
def autoload(self, source_or_url=None, source=None, url=None): if len([a for a in [source_or_url, source, url] if a is not None]) != 1: raise ScriptError("splash:autoload requires a single argument") if source_or_url is not None: source_or_url = source_or_url.strip() if source_or_url.startswith(("http://", "https://")): source, url = None, source_or_url else: source, url = source_or_url, None if source is not None: # load source directly self.tab.autoload(source) return ImmediateResult(True) else: # load JS from a remote resource cmd_id = next(self._command_ids) def callback(reply): if reply.error(): reason = REQUEST_ERRORS_SHORT.get(reply.error(), '?') self._return(cmd_id, None, reason) else: source = bytes(reply.readAll()) self.tab.autoload(source) self._return(cmd_id, True) return AsyncBrowserCommand(cmd_id, "http_get", dict(url=url, callback=callback))
def go(self, url, baseurl=None, headers=None): if url is None: raise ScriptError("'url' is required for splash:go") if self.tab.web_page.navigation_locked: return ImmediateResult((None, "navigation_locked")) cmd_id = next(self._command_ids) def success(): try: code = self.tab.last_http_status() if code and 400 <= code < 600: # return HTTP errors as errors self._return(cmd_id, None, "http%d" % code) else: self._return(cmd_id, True) except Exception as e: self._return(cmd_id, None, "internal_error") def error(error_info): self._return(cmd_id, None, self._error_info_to_lua(error_info)) return AsyncBrowserCommand( cmd_id, "go", dict( url=url, baseurl=baseurl, callback=success, errback=error, headers=self.lua.lua2python(headers, max_depth=3), ))
def set_resource_timeout(self, timeout): if timeout is None: timeout = 0 timeout = float(timeout) if timeout < 0: raise ScriptError("splash.resource_timeout can't be negative") self.tab.set_resource_timeout(timeout)
def wrapper(self, *args, **kwargs): try: return meth(self, *args, **kwargs) except ScriptError as e: self._exceptions.append(e) raise except BaseException as e: self._exceptions.append(ScriptError(e)) raise
def http_get(self, url, headers=None, follow_redirects=True): if url is None: raise ScriptError("'url' is required for splash:http_get") cmd_id = next(self._command_ids) def callback(reply): reply_har = reply2har(reply, include_content=True, binary_content=True) self._return(cmd_id, self.lua.python2lua(reply_har)) return AsyncBrowserCommand(cmd_id, "http_get", dict( url=url, callback=callback, headers=self.lua.lua2python(headers, max_depth=3), follow_redirects=follow_redirects, ))
def set_user_agent(self, value): if not isinstance(value, basestring): raise ScriptError( "splash:set_user_agent() argument must be a string") self.tab.set_user_agent(value)
def set_result_content_type(self, content_type): if not isinstance(content_type, basestring): raise ScriptError( "splash:set_result_content_type() argument must be a string") self._result_content_type = content_type
def set_timeout(self, timeout): timeout = float(timeout) if timeout < 0: raise ScriptError("request:set_timeout() argument can't be < 0") self.request.timeout = timeout
def set_result_status_code(self, code): if not isinstance(code, int) or not (200 <= code <= 999): raise ScriptError( "splash:set_result_status_code() argument must be a number 200 <= code <= 999" ) self._result_status_code = code