ajax抓取网页内容(Pythonselenium3.14为什么selenium不能直接拦截请求呢?(图))

优采云 发布时间: 2021-12-27 00:04

  ajax抓取网页内容(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请求。先记录一下信息:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线