安装Splash是一个类似selenium的自动化浏览器,但又与selenium有很大区别:比如splash是异步的,splash暴露了httpAPI来自动化操作。安装很简单,需要先安装docker,然后拉取镜像:sudodockerpullscrapinghub/splash启动splash:sudodockerrun-it-p8050:8050--rmscrapinghub/splash另外,你也可以将容器中的目录映射到Local,这样可以保证数据的持久化,否则下次新容器的配置会变,容器中主要有四个目录:/etc/splash/filters:存放过滤器的文件夹/etc/splash/proxy-profiles:存放代理配置的文件夹/etc/splash/js-profiles:存放js脚本的文件夹/etc/splash/lua_modules:存放lua脚本的文件夹映射到本地的命令是(-v表示映射文件文件夹),其他类似:dockerrun-p8050:8050-v本地绝对路径:/etc/splash/filtersscrapinghub/splashSplashHTTPAPI我们可以通过发送某种HTTP请求让splash执行相应的操作,例如:我们输入127.0.0.1:8050/render.html?url=https://www.b浏览器中的aidu.com可以让Splash访问百度,浏览器显示的内容就是Splash返回的内容。但是有什么用呢?注意splash返回的是js渲染过的页面,也就是说可以加载动态页面,明白有什么用。Splash的httpapi支持get和post。部分参数可以作为get参数发送,也可以作为post内容发送(注意格式为json,请求头建议添加Content-Type:application/json)render.html返回渲染页面的HTML参数为如下:url:string,要访问的URLbaseurl:如果页面中的某些资源包含相对URL,则需要使用该参数填写前面的部分。timeout:浮点数,超时时间resource_timeout:单次请求的超时时间,注意既然会渲染页面,就说明splash访问url肯定不是请求,其中还包括很多ajax、js和image加载。wait:页面加载完成后的等待时间。通常,指定一个较小的值(0.5)以防止不必要的异常。proxy:代理,格式为[protocol://][user:password@]proxyhost[:port],协议可以是http或者socks5js:需要执行的js配置文件名,即/etc/splash/js-profiles目录下的文件名js_source:需要执行的js代码filters:/etc/splash/filters保存的filter的文件名,支持多个逗号分隔。allowed_domains:允许访问的域名列表(以逗号分隔)allowed_content_types:允许加载的内容类型列表,支持*、?、[]、[!]四种通配符语法,详见fnmatchforbidden_??content_types:禁止加载的内容类型,我试过这两个参数没有作用,是不是姿势不对。viewport:网页大小,格式为1024x768(默认)images:是否下载图片。因为有缓存,所以返回的截图也可能加载了图片,但是加载的是本地缓存,而不是请求外网。headers:第一次发出请求时设置的请求头,只有post方法支持该参数body:如果目标请求是POST,则该参数为POST请求文本cache列表会在响应头中返回X-Splash-Saved-Arguments:name1=9a6747fc6259aa374ab4e1bb03074b6ec672cf99;name2=ba001160ef96fe2a3f938fea9e6762e204a562b3和这个内容类似,下一个请求可以通过load_args传递相同的请求头来加载。一般没有,js_source或者lua_source比较方便。load_args:加载save_args保存的参数名列表。format可以是save_args返回的responseheader,按照requestheader的格式发送,也可以是name1和value组成的json对象。html5_media:是否播放视频,默认0禁用http2:是否启用http2,默认0engine:使用的浏览器引擎,默认是webkit,也可以是chromium。不建议修改。render.png返回js渲染页面的png截图。除了render.html,还有:width:widthheight:widthrender_all:是否全屏,默认0scale_method:raster(按像素缩放,默认)和vector(按元素缩放)。Vector的性能更高,字体更清晰,元素边界更明显。但可能会出现未知问题,请谨慎使用。render.jpeg参数和render.png一样,有:quality:JPEG图片的质量,取值范围0-100,默认75,不建议超过95。render。har返回HAR格式(什么是har格式,自己百度)参数同render.html附加参数:request_body:是否包含请求内容,默认0response_body:是否包含响应内容,默认0render.json返回一个用javascript渲染的网页一个json编码的信息字典。参数同render.jpeg,html:是否包含HTML,默认0png:是否包含PNG,默认0jpeg:是否包含JPEG,默认0iframes:是否包含子iframe信息,默认0script:是否包含包含执行的js结果,默认0console:是否包含js控制台消息,默认0history:是否包含历史响应,默认0har:是否包含HAR数据,默认0request_body:如果值为1,返回结果将包含har记录和请求内容response_body:如果值为1,返回结果将包含har记录和响应内容。execute执行自定义脚本并返回结果lua_source:lua脚本字符串timeout:同上allowed_domains:同上proxy:同上filters:同上save_args:同上load_args:同上run参数和功能同上execute,区别在于脚本的格式。执行脚本必须包含在主函数中,而运行脚本可以是一个单独的语句。示例脚本如下:executescriptfunctionmain(splash,args)assert(splash:go(args.url))assert(splash:wait(1.0))returnsplash:html()endrunscriptassert(splash:go(args.url))assert(splash:wait(1.0))returnsplash:html()allowcrossdomaindockerrun-it-p8050:8050scrapinghub/splash--js-cross-domain-access有两种执行方式网页中的js代码:1.使用js_source参数或render.html中的js参数加载指定的js文件。示例(推荐使用POST请求):curl-XPOST-H'content-type:application/json'\-d'{"js_source":"document.title=\"MyTitle\";","url":"http://example.com"}'\'http://localhost:8050/render.html'2、带有指定的请求头curl-XPOST-H'content-type:application/javascript'\-d'document.title="我的标题";'\'http://localhost:8050/render.html?url=http://domain.com'如果想获取js执行的结果,需要使用render.json将script参数设置为1Request过滤器Splash支持根据AdblockPlus规则过滤请求。您可以使用它的easylist.txt来删除广告,或者手动编写它来阻止某些请求。比如防止加载自定义字体文件,可以这样写:.ttf|.woff|然后把这个文件命名为nofonts.txt,使用docker打开splash时将filter目录映射到本地(上面介绍了如何map),然后把nofonts.txt放到这个目录下。发起请求只需要携带参数filters=nofonts执行过滤规则,例如:curl'http://localhost:8050/render.png?url=http://domain.com/page-with-fonts.html&filters=nofonts'另外如果filter目录下有default.txt文件,会自动启用。当然,如果不想启用,可以设置filters=none。自定义过滤器的语法可以参考:https://help.eyeo.com/en/adblockplus/how-to-write-filtersProxyProfiles(代理配置文件)和过滤规则一样,需要映射代理配置目录先到本地,然后把代理配置文件放到该目录下。示例配置文件:[proxy];代理IP和端口,分号是注释host=proxy.crawlera.comport=8010;代理认证,默认为空username=usernamepassword=password;代理类型,默认HTTP,也支持socks5type=HTTP[rules];使用代理白名单,默认.*whitelist=.*mywebsite\.com.*;使用代理黑名单,默认为空blacklist=.*\.js.*.*\.css.*。*\.png然后将proxy目录下的文件保存为myproxy.ini(任意名称),然后在请求中添加proxy=myproxy参数即可。另外,只有在白名单中且不再在黑名单中的才会使用代理,即如果黑名单和白名单同时匹配,则黑名单的优先级更高。可以看出代理文件的规则很简单,就是正则表达式之间用换行符分隔。此外,如果存在default.ini,则默认情况下启用它。使用proxy=none禁用。_gc回收内存并清理缓存,只支持POST请求,示例:curl-XPOSThttp://localhost:8050/_gc_debug获取Splash实例的调试信息(最大使用的RSS数,使用的文件描述符数,activerequests,Requestqueuelength,activeobjects数量),GET方式请求。curlhttp://localhost:8050/_debug_ping要pingSplash实例,向/_ping端点发送GET请求,示例:curlhttp://localhost:8050/_pingluascript如果使用execute接口执行lua脚本,格式需要遵循:functionmain(splash,args)splash:go("http://example.com")splash:wait(0.5)localtitle=splash:evaljs("document.title")return{title=title}end另外关于一些lua的API可以直接参考:官方文档,写的很详细,通俗易懂。scrapy-splash如果你想把scrapy和splash整合在一起,你会写什么?很简单,就像集成selenium一样,加一个splash中间件。其实访问的是url,splash其实是访问http://splashURL/render.html?...,其他没变,所以我们只需要替换中间件中的url,但是splash还有一些参数怎么传递给中间件呢?只需使用request.meta。至于scrapy-splash,我就不详细介绍了。只需要在settings.py中配置一些参数,然后在spider中将splash的参数添加到meta中即可。当然,你也可以使用SplashRequest。SplashRequest其实就是把参数保存在meta里面,做一个包。SPLASH_URL='http://192.168.59.103:8050'DOWNLOADER_MIDDLEWARES={'scrapy_splash.SplashCookiesMiddleware':723,'scrapy_splash.SplashMiddleware':725,'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware':810,}SPIDER.SplashDeduplicateArgsMiddleware':100,}DUPEFILTER_CLASS='scrapy_splash.SplashAwareDupeFilter'HTTPCACHE_STORAGE='scrapy_splash.SplashAwareFSCacheStorage'请请求示例:yieldscrapy.Request(url,self.parse_result,meta={'splash':{#arg在此处呈现参数'html':1,'png':1,#'url'是从请求url预填充的#'http_method'设置为POST请求的'POST'#'body'设置为POST请求的请求主体},#可选参数'endpoint':'render.json',#可选;默认为render.json'splash_url':'
