splash官方文檔解讀(翻譯)

安裝

splash是一個類似於selenium的自動化瀏覽器,不過它與selenium還是有很大區別的:比如splash是異步的,splash暴露httpAPI來自動化操作。

安裝很簡單,需要先安裝docker,然後拉取鏡像:
sudo docker pull scrapinghub/splash
啓動splash:
sudo docker run -it -p 8050:8050 --rm scrapinghub/splash
另外,還可以把容器內的目錄映射到本地,這樣你就可以修改本地文件夾內的文件來作用於容器,容器內有四個主要目錄:

  • /etc/splash/filters:存放過濾器的文件夾
  • /etc/splash/proxy-profiles:存放代理配置的文件夾
  • /etc/splash/js-profiles:存放js腳本的文件夾
  • /etc/splash/lua_modules:存放lua腳本的文件夾

映射到本地的命令是(-v就表示映射文件夾),其他類似:
docker run -p 8050:8050 -v 本地絕對路徑:/etc/splash/filters scrapinghub/splash

Splash HTTP API

我們可以通過發送某種HTTP請求來使splash執行相應的操作,舉個例子:
我們在瀏覽器輸入127.0.0.1:8050/render.html?url=https://www.baidu.com這樣你就可以讓splash訪問百度了,瀏覽器顯示的內容就是splash返回的內容。但這有什麼用呢?注意splash返回的是已經經過js渲染的頁面,也就是說它可以加載動態頁面,明白有什麼用了吧。

splash 的httpapi既支持get也支持post,其中的一些參數可以作爲get的參數發送,也可以作爲post的內容發送(注意格式爲json,而且請求頭建議加入Content-Type: application/json)

render.html

返回渲染後頁面的HTML
參數如下:

  • url:字符串,要訪問的URL

  • baseurl:如果頁面中某些資源包含相對URL,需要使用這個參數來填充前面那部分。

  • timeout:浮點數,超時時間

  • resource_timeout :單個請求的超時時間,注意既然是會渲染頁面,說明splash訪問URL肯定不是一次請求,其中還包含很多ajax、js和圖片的加載。

  • wait:頁面加載後的等待時間,一般情況下都會指定一個較小的值(0.5)來防止一些不必要的異常

  • proxy:代理,格式爲[protocol://][user:password@]proxyhost[:port],protocol可以是http,也可以是socks5

  • js:需要執行js配置文件名稱,也就是/etc/splash/js-profiles目錄下的文件名稱

  • js_source :需要執行的js代碼

  • filters:/etc/splash/filters存放的過濾器的文件名稱,支持多個以逗號分隔。

  • allowed_domains:允許訪問的域名列表(以逗號分隔)

  • allowed_content_types: 允許加載的內容類型列表,支持* 、?、[]、[!]四種通配符語法,具體參考fnmatch

  • forbidden_content_types:禁止加載的內容類型,我試了一下這兩個參數沒效果,難道是姿勢不對。

  • viewport :網頁大小,格式爲1024x768(默認)

  • images:是否下載圖片。因爲有緩存,所以返回的截圖可能也是加載了圖片的,只是加載的本地緩存而不是請求互聯網。

  • headers:爲第一個傳出的請求設置的請求頭,僅post方法支持該參數

  • body:如果目標請求是POST,該參數是POST請求正文

  • http_method:請求方法,默認GET

  • save_args:要放入緩存的參數名稱列表,會在響應頭中返回X-Splash-Saved-Arguments: name1=9a6747fc6259aa374ab4e1bb03074b6ec672cf99;name2=ba001160ef96fe2a3f938fea9e6762e204a562b3類似這樣的內容,下次請求可以通過load_args傳遞相同的請求頭來加載。一般用不上,js_source或lua_source 更方便。

  • load_args:加載save_args保存的參數名稱列表,格式可以是save_args返回的響應頭,並以請求頭的格式發送,也可以是name1和值組成的json對象

  • html5_media:是否播放視頻,默認0關閉

  • http2:是否啓用http2,默認0

  • engine :要使用的瀏覽器引擎,默認webkit,也可以是chromium。不建議修改。

render.png

返回js渲染後的頁面png截圖
參數除了render.html一樣,還有:

  • width:寬度
  • height : 寬度
  • render_all : 是否全屏,默認0
  • scale_method : raster(逐像素縮放,默認)和vector(按元素縮放)。vector性能更高,字體更清晰,元素邊界更明顯。但是可能出現未知的問題,請謹慎使用。

render.jpeg

參數同render.png,還有:

  • quality : JPEG圖片的質量,取值範圍0-100,默認75。不建議大於95。

render.har

以HAR格式返回(什麼是har格式可以自行百度)
參數與render.html相同
額外參數:

  • request_body:是否包含請求內容,默認0
  • response_body:是否包含響應內容,默認0

render.json

返回帶有javascript渲染網頁信息的json編碼字典。
參數同render.jpeg,還有

  • html : 是否包含HTML,默認0
  • png : 是否包含PNG,默認0
  • jpeg :是否包含JPEG,默認0
  • iframes :是否包含子iframe的信息,默認0
  • script : 是否包含執行的js結果,默認0
  • console : 是否包含js控制檯消息,默認0
  • history : 是否包含歷史響應,默認0
  • har :是否包含HAR數據,默認0
  • request_body :如果值爲1,返回結果將包含har記錄,而且包含請求內容
  • response_body :如果值爲1,返回結果將包含har記錄,而且包含響應內容

execute

執行自定義腳本並返回結果

  • lua_source : lua腳本字符串
  • timeout : 同上
  • allowed_domains :同上
  • proxy :同上
  • filters :同上
  • save_args : 同上
  • load_args :同上

run

參數和作用同execute,區別在於腳本的格式。execute腳本必須包含在main函數中,而run腳本則可以是單獨的語句,示例腳本如下:

execute腳本

function main(splash, args)
    assert(splash:go(args.url))
    assert(splash:wait(1.0))
    return splash:html()
end

run腳本

assert(splash:go(args.url))
assert(splash:wait(1.0))
return splash:html()

允許跨域

docker run -it -p 8050:8050 scrapinghub/splash --js-cross-domain-access

在網頁中執行js代碼

有兩種方法:
1、使用render.html中的js_source參數或者js參數加載指定js文件,示例(建議使用POST請求):

curl -X POST -H 'content-type: application/json' \
    -d '{"js_source": "document.title=\"My Title\";", "url": "http://example.com"}' \
    'http://localhost:8050/render.html'

2、帶有指定請求頭

curl -X POST -H 'content-type: application/javascript' \
    -d 'document.title="My Title";' \
    'http://localhost:8050/render.html?url=http://domain.com'

如果要獲取js執行的結果,需使用render.json將script參數設置爲1

請求過濾器(Request Filters)

Splash支持根據Adblock Plus規則過濾請求。你可以使用其easylist.txt
來刪除廣告,或者手動編寫來阻止某些請求。例如阻止自定義字體文件的加載可以這些寫:

.ttf|
.woff|

然後將這個文件命名爲nofonts.txt,並在使用docker開啓splash的時候將過濾器目錄映射到本地(上面有說怎麼映射),接着將nofonts.txt放在這個目錄。發起請求只需攜帶參數filters=nofonts就可以執行過濾器規則,例如:

curl 'http://localhost:8050/render.png?url=http://domain.com/page-with-fonts.html&filters=nofonts'

另外如果過濾器目錄存在default.txt文件,則會自動啓用。當然如果你不想啓用,可以設置filters=none。關於自定義過濾器的語法請參考:https://help.eyeo.com/en/adblockplus/how-to-write-filters

代理配置文件(Proxy Profiles)

同過濾器規則,需先將代理配置目錄映射到本地,接着講代理配置文件放入目錄。示例配置文件:

[proxy]

; 代理IP和端口,分號爲註釋
host=proxy.crawlera.com
port=8010

; 代理驗證,默認爲空
username=username
password=password

; 代理類型,默認HTTP,還支持socks5
type=HTTP

[rules]
;使用代理的白名單,默認.*
whitelist=
    .*mywebsite\.com.*

; 使用代理的黑名單, 默認爲空
blacklist=
    .*\.js.*
    .*\.css.*
    .*\.png

接着將文件保存在代理目錄爲myproxy.ini(名稱任意),然後只需在請求加入proxy=myproxy參數即可。另外,只有在白名單中並且不再黑名單中的纔會使用代理,也就是說如果黑名單和白名單同時匹配,黑名單優先級更高。

可以看出代理文件的規則很簡單,也就是正則編寫的表達式以換行分隔就行了。另外,如果存在default.ini,則默認啓用。使用proxy=none禁止。

_gc

回收內存清理緩存,只支持POST請求,示例:
curl -X POST http://localhost:8050/_gc

_debug

獲取有關Splash實例的調試信息(使用的RSS數量上限,使用的文件描述符數量,活動請求,請求隊列長度,活動對象的數量),以GET方式請求。
curl http://localhost:8050/_debug

_ping

要ping Splash實例,向/_ping端點發送GET請求,示例:
curl http://localhost:8050/_ping

lua腳本

如果以execute接口來執行lua腳本的話,格式需要遵循:

function main(splash, args)
  splash:go("http://example.com")
  splash:wait(0.5)
  local title = splash:evaljs("document.title")
  return {title=title}
end

另外關於一些lua的API可以直接參考:官方文檔,寫的很詳細,很容易看懂。

scrapy-splash

如果你想將scrapy和splash整合在一起會怎麼寫?很簡單,就像整合selenium一樣添加一個splash中間件。

實際訪問URL,splash其實就是在訪問http://splashURL/render.html?url=URL,其他都沒有變化所以我們只需在中間件中替換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_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

請求示例:

yield scrapy.Request(url, self.parse_result, meta={
    'splash': {
        'args': {
            # set rendering arguments here
            'html': 1,
            'png': 1,

            # 'url' is prefilled from request url
            # 'http_method' is set to 'POST' for POST requests
            # 'body' is set to request body for POST requests
        },

        # optional parameters
        'endpoint': 'render.json',  # optional; default is render.json
        'splash_url': '<url>',      # optional; overrides SPLASH_URL
        'slot_policy': scrapy_splash.SlotPolicy.PER_DOMAIN,
        'splash_headers': {},       # optional; a dict with headers sent to Splash
        'dont_process_response': True, # optional, default is False
        'dont_send_headers': True,  # optional, default is False
        'magic_response': False,    # optional, default is True
    }
})

更多參考:https://github.com/scrapy-plugins/scrapy-splash

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章