前言
因为最近要写一个抓取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