ajax抓取网页内容(Pythonselenium3.14为什么selenium不能直接拦截请求呢?(图))
优采云 发布时间: 2021-12-27 00:04ajax抓取网页内容(Pythonselenium3.14为什么selenium不能直接拦截请求呢?(图))
部门需要一个自动化脚本来完成web端接口功能的冒烟,需要在页面加载时抓取ajax请求,从接口层面判断请求是否成功。查阅了大量资料,没有人有处理相关问题的经验,过程中坑也很多,所以如果你也有这个需求,继续往下看吧~
环境和语言:
Python
硒3.14
为什么selenium不能直接拦截请求体?这是Chrome官方故意做的。详情请参考此网址:
%20response%20body&can=1
在网上搜索后,找到了三种解决方法:
1、 取代理,拦截代理级别的日志请求;如果proxy过期了,请求会变得很慢,所以没有采用,有需要的可以自己研究。
2、使用硒线。这是 GitHub 上的一个开源项目。可以直接拦截response_code和body。原理大概就是看源码了。它也应该是一个代理,但这个项目是为你打包的。
当时看到真的很激动,所有的问题都通过pip install解决了。但是当我怀着极大的兴趣运行代码时,发现网页报错:err_proxy_connection_failed。感觉莫名其妙,跑到开源项目中寻找答案。这不仅发生在我身上,也可以说是这个开源项目的一个bug。到目前为止还没有关闭。我很久没有放弃调试,但是这条路走不通,只好流泪放弃。事实证明,不要只相信一颗星星只有一两百颗星星。开源代码放在下面,万一你能通过:
3、开启selenium性能捕获,可以在性能日志中进行修改拦截response_body:
先总结一下总体思路:
结合selenium和Chrome devtool:selenium可以打开性能日志,根据性能日志中的Network.responseReceived事件抓取requestId和对应的url,然后结合selenium提供的execute方法传入requestId参数来获取相应的身体反应。
execute_cdp_cmd()方法的源码里有例子,讲的很清楚,可以去看看。本文还将给出代码示例:
1 caps = DesiredCapabilities.CHROME
2 caps['goog:loggingPrefs'] = {'performance': 'ALL'}
3
4 def driver():
5 global driver
6 driver = webdriver.Chrome(desired_capabilities=caps)
7 driver.maximize_window()
请注意第二行代码,这是我踩到的第一个坑:
很多教程中给出的代码如下:
caps['loggingPrefs'] = {'performance':'ALL'},用这段代码打开性能日志,但是这样运行会报错,原因来自chromedriver,75.< @k27@从>3770.8开始,一定要这样运行。
注意只打开性能日志还是不能抓到正文。如果你的需求只是判断状态码,那么上面的方案就足够了。
1、为什么需要获取requestid:
Chrome性能日志的获取需要配合Chrome DevTool方法使用。本文档详细列出了 Chrome 提供的域。在域网络下,您可以选择所需的方法:
在这里,我选择了我需要的方法,如下图所示,可以看到,这里需要传入一个名为requestId的参数,它是唯一的请求ID,当我们可以抓取到我们想要的body时我们明白了。但我从未听说过这个 requestId。我可以从哪里得到它?这时候就需要对抓取到的性能日志中的事件进行分析。
2、 关于Chrome返回的日志事件,可以参与这个博客,里面有详细的介绍。基于这个博客(.),我分析了我要使用的事件-Network.responseReceived,其中收录
requestid。返回值。
1 def parse_response_body(driver):
2 """获取requestid"""
3 browser_log = driver.get_log('performance')
4 events = [_process_browser_log_entry(entry) for entry in browser_log]
5 events_response = [event for event in events if 'Network.responseReceived' == event['method']] # 根据Network.responseReceived这个network,解析出requestId
6 for res in events_response:
7 requestId = res["params"]["requestId"]
3、总结一下,结合selenium中的方法:
1 def execute_cdp_cmd(driver, cmd, cmd_args):
2 return driver.execute("executeCdpCommand", {'cmd': cmd, 'params': cmd_args})['value']
3
4
5 response_body = driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': requestId}
接下来就很简单了,抓取body,然后用json解析。就在我满怀信心的时候,现实又给了我沉重的一击。在抓取请求体的过程中,程序报错。
未找到具有给定标识符的资源
这是我踩过的最大的坑。它困扰了我五六个小时。我以为是我的代码有问题。一直在调试,在网上找问题,最后在一篇不太相关的js博客里。对于这句话:getResponseBody will error发生在查询什么都不返回时...
回到界面,手动获取了当前运行页面的ajax请求,结果都是没有返回体的请求ORZ。
果断地尝试……除了……,然后程序运行得很漂亮!此刻的心情真是激动的想哭。
后记:
这种需求感觉很普遍。毕竟界面元素能不能加载成功,是看界面返回最直接可靠的方式,但是不知道为什么国内好像没有相关的博客(可能是我没有搜索过了)。所以想记录下这篇文章,希望有需要的朋友不要走那么多弯路,轻松解决问题~~
PS:在FQ的过程中,我也找到了将selenium升级到4的方案,因为selenium 4开始和Chrome DevTools一起支持收购了。但是,只找到了 Java 示例。因为对Java不是很熟悉,所以被抛弃了。他们在这里为每个人提供。如果你需要它,你可以拿起它:
@ohanaadi/chrome-devtools-and-selenium-4-eadab5d755b7
-----------------------我是分割线 2021/02/01----------------- - ---------
今天在看技术博客的时候发现了一个开源项目,是一个被proxy拦截的ajax请求。先记录一下信息: