前言
因為最近要寫一個抓取sitemap和相應的參數的小腳本,現有的爬蟲無論用什么語言寫的,幾乎都無法抓取參數,所以我思考了一下,先做一個簡單的總結。
本來以為寫個這種sitemap的爬蟲很簡單,經過思考之后才發現其中的可怕之處,最關鍵的是參數的提取,這個太麻煩了。。。這個時候才發現AWVS的無敵和強大之處。。。
如果我們要獲取網站的sitemap同時還要抓取對應鏈接的參數,我大概總結了url的幾個來源:
1、頁面上直接現有的form表單以及現有的href等指向的鏈接及參數,這個相對比較簡單,不過要考慮post和get的問題。
2、由js生成的DOM中的form表單和href指向的鏈接
3、由js發起的訪問請求,例如AJAX請求等
4、通過點擊然后調用js發送請求,或是點擊生成一個form或是生產一個DOM,然后再點擊再由js發送請求。例如如下代碼
1
2
3
4
|
< div > < input id = "searchTitle" name = "searchTitle" value = "" type = "text" > < div class = "button" onclick = "javascript:searchWeb();" ></ div > </ div > |
5、通過setTimeout函數延遲觸發的js的請求,例如setTimeout("request()", 2000);,這一類我暫時還沒有太好的辦法解決,不過有初步的辦法,后面會說到。
目前我大概想到這么五類,肯定還有沒考慮到的地方,并且目前實際的代碼還沒有寫出來,我先記錄一下我的想法,要是有哪位師傅有興趣請務必聯系我。。。。orz。。
要解決上述的5個問題,因為我的工程的前半部分使用python寫的,所以這里我需要用python來解決,那么最佳選擇必然是selenium和phantomjs,其實比起來我更想用原生的phantomjs來寫。
用phantomjs的話第一個和第二個問題不攻自破,直接正則匹配下來就行了,因為它會幫我們先把頁面的js執行了。
第三個問題也相對比較好解決,我們通過原生phantomjs的APIonResourceRequested就能夠監控所有從頁面發出去的請求。
然后再來看第四個問題,我目前的想法應該沒有辦法徹底解決,我們同樣可以用phantomjs向頁面的所有的dom發送一個click事件,但是這樣子的話時間是一個很大的問題,所以初步想法向所有具有onclick事件的標簽發送點擊事件
然后再來看第五個問題,這應該是最麻煩的一個,我初步的想法還是用onResourceRequested事件,然后設置一個超時時限,讓頁面執行個幾秒鐘,但是最后我還是放棄了這個想法,我決定忽視這個問題,因為如果每個頁面都等上幾秒那時間耗費不堆上天了。
以上就是我目前初步的一些思考,還有很多不成熟之處。
selenium與phantomjs聯動的問題
之前一直知道有selenium這個東西,不夠因為沒有地方需要,也沒有可以去學習,不過對phantomjs可能會稍微熟悉一些。
先寫個簡單的程序
1
2
3
4
5
6
7
8
9
10
|
from selenium import webdriver service_args = [] service_args.append( '--load-images=no' ) ##關閉圖片加載 service_args.append( '--disk-cache=yes' ) ##開啟緩存 service_args.append( '--ignore-ssl-errors=true' ) ##忽略https錯誤 d = webdriver.PhantomJS( "phantomjs" ,service_args = service_args) d.get( "http://xxxxxxxxxxxxxxxxxxxxx" ) print d.page_source d.quit() |
這樣就可以發送get請求了。
問題一:沒有post請求?
我覺得應該是我還了解的不夠。不過翻了API,確實沒有找到,希望大家能夠指出我的錯誤,但我真的好像沒有找到能夠發送post請求的地方,真是蠢爆了。。
這里我想到了兩種方法解決,先說一種,第二種留到后面說。
就是用requests庫遞交post請求,拿下來的cookie,調用add_cookie函數給它,然后讓它帶著cookie發送get請求就好了。
樣例如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
from selenium import webdriver import requests r = requests.session() service_args = [] service_args.append( '--load-images=no' ) ##關閉圖片加載 service_args.append( '--disk-cache=yes' ) ##開啟緩存 service_args.append( '--ignore-ssl-errors=true' ) ##忽略https錯誤 d = webdriver.PhantomJS( "phantomjs" ,service_args = service_args) data = { "username" : "123" , "password" : "123" , "login" : "1" } result = r.post( "http://127.0.0.1:8000/web/login.php" ,data = data) cookies = r.cookies.get_dict() for i in cookies: d.add_cookie({ 'name' : i, 'value' :cookies[i], 'path' : '/' , 'domain' : '127.0.0.1' }) d.get( "http://127.0.0.1:8000/web/index.php" ) print d.page_source d.quit() |
另外這個add_cookie函數還比較刁鉆,還要把path和domain都設置好,不然有時會報錯。
第二個方法的話,我們知道,如果用原生PhantomJS的話,我們可以很容易遞交post請求,比如如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var webPage = require( 'webpage' ); var page = webPage.create(); var settings = { operation: "POST" , header:{}, data: "username=123&password=123&login=1" }; page. open ( 'http://127.0.0.1:8000/web/login.php' , settings, function(status) { / / console.log(page.content); for (var i = 0 ;i<page.cookies.length;i + + ){ console.log(page.cookies[i].name + ":" + page.cookies[i].value) } }); |
所以我們想辦法就是直接在 Selenium中讓PhantomJS 執行它的 API就可以了,這里不貼了,看完下一小節就知道怎么寫了。
問題二:在 Selenium中獲取PhantomJS 的API的執行結果?
還好Selenium帶了個get_log函數,比如我監控'http://127.0.0.1:8000/web/index.php‘頁面向外發送的所有請求,如果用原生的phantomjs,很好辦,如下:
1
2
3
4
5
6
7
8
|
var webPage = require( 'webpage' ); var page = webPage.create(); page.onResourceRequested = function (request) { console.log( 'Request ' + request.url); }; ........... ........... |
所以我們直接在Selenium中調用PhantomJS 的API就好了。如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
from selenium import webdriver import requests r = requests.session() service_args = [] service_args.append( '--load-images=no' ) ##關閉圖片加載 service_args.append( '--disk-cache=yes' ) ##開啟緩存 service_args.append( '--ignore-ssl-errors=true' ) ##忽略https錯誤 d = webdriver.PhantomJS( "phantomjs" ,service_args = service_args) data = { "username" : "123" , "password" : "123" , "login" : "1" } result = r.post( "http://127.0.0.1:8000/web/login.php" ,data = data) cookies = r.cookies.get_dict() for i in cookies: d.add_cookie({ 'name' : i, 'value' :cookies[i], 'path' : '/' , 'domain' : '127.0.0.1' }) script = "var page=this;page.onResourceRequested = function (request){console.log(request.url);};" d.command_executor._commands[ 'executePhantomScript' ] = ( 'POST' , '/session/$sessionId/phantom/execute' ) d.execute( 'executePhantomScript' , { 'script' : script, 'args' : []}) d.get( "http://127.0.0.1:8000/web/index.php" ) print d.page_source d.quit() |
這里上述代碼確實能夠實時執行,但是就這樣寫的話沒有辦法獲取到結果。
這里需要用到一個get_log函數,改進如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
from selenium import webdriver import requests r = requests.session() service_args = [] service_args.append( '--load-images=no' ) ##關閉圖片加載 service_args.append( '--disk-cache=yes' ) ##開啟緩存 service_args.append( '--ignore-ssl-errors=true' ) ##忽略https錯誤 d = webdriver.PhantomJS( "phantomjs" ,service_args = service_args) data = { "username" : "123" , "password" : "123" , "login" : "1" } result = r.post( "http://127.0.0.1:8000/web/login.php" ,data = data) cookies = r.cookies.get_dict() for i in cookies: d.add_cookie({ 'name' : i, 'value' :cookies[i], 'path' : '/' , 'domain' : '127.0.0.1' }) script = "var page=this;page.onResourceRequested = function (request){page.browserLog.push(request.url);};" d.command_executor._commands[ 'executePhantomScript' ] = ( 'POST' , '/session/$sessionId/phantom/execute' ) d.execute( 'executePhantomScript' , { 'script' : script, 'args' : []}) d.get( "http://127.0.0.1:8000/web/index.php" ) print d.page_source print d.get_log( 'browser' ) d.quit() |
在js腳本中我們調用page.browserLog.push,然后在python腳本中我們get_log('browser')去獲取就可以實現相互溝通,當然肯定還有別的辦法,不過我沒有找到。。。。僵硬了。。。。
后記
再說這個抓取sitemap和請求參數的小腳本,想了想還是覺得非常麻煩,雖然幾個問題都有了相應的解決辦法,也不管好壞,加上今天稍微研究了一下python調用phantom的優化,還是稍微有點信心了,但是感覺要整合到一起來還是會很麻煩,效率問題是一個,能否真正準確抓取完整又是另一個,慢慢來把,沒想到最初覺得不是問題的問題最后卻成了我最大的麻煩之一。。僵硬。。。最后還要說的是原聲的phantomjs真的比selenium去調用舒服得多。。。現在想來要是最開始想把每個環節思考一下就好了,要是思考了大概就不會用python了,大概會用nodejs,對了,最近稍微研究了一下nodejs的一些滲透和攻擊方法,后續整理一下分享出來,希望師傅們能夠幫忙指點指點。
以上這篇selenium在執行phantomjs的API并獲取執行結果的方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/qq_19876131/article/details/70182302