安裝
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
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/145103.html
標籤:Python
上一篇:scrapy 自定義命令
