利用selenium抓取网页的ajax请求
部门需要一个自动化脚本,完成web端界面功能的冒烟,并且需要抓取加载页面时的ajax请求,从接口层面判断请求是否成功。查阅了很多资料都没有人有过相关问题的处理经验,在处理过程中也踩了很多坑,所以如果你也有这个需要,就继续往下看吧~
环境及语言:
Python
selenium3.14
为什么selenium不能直接拦截请求body呢?这是Chrome官方故意而为之的,详情可参考这个网址:
https://bugs.chromium.org/p/chromedriver/issues/detail?id=2267&q=performance%20response%20body&can=1
上网引擎搜索后,找到的解决方案有以下三种:
1、走代理,在代理层面截取日志请求;这个如果代理过期,请求就会变得巨慢,所以没有采用,有需要可以自行研究。
2、用selenium-wire,这个是一个GitHub上的开源项目,可以直接截取response_code和body,原理大概翻了一下源码,应该走的也是代理,只不过这个项目替你封装好了。
当时看到的时候真是激动坏了,pip install一下, 问题全部解决。但是当我兴致满满的运行代码时,发现网页报错: err_proxy_connection_failed.心凉了一大半,去开源项目下寻求答案,这个原来不止我这边发生过,可以说是这个开源项目的一个bug,至今为止未被close。不死心的调试了很久,都没能走通这条路,所以含泪放弃。事实说明,还是不要随便相信star只有一两百颗星的项目。开源代码放在下面,万一你那里能走通呢:
https://github.com/wkeeling/selenium-wire
3、开启selenium的性能抓取,在性能日志里面可以做改动,以拦截response_body:
整体的一个思路先概括一下:
结合selenium与Chrome devtool:selenium可开启性能日志,根据性能日志中的Network.responseReceived事件抓取requestId和对应的url ,然后结合selenium提供的execute方法,传入requestId参数,即可获得对应的body回参。
execute_cdp_cmd()方法的源码里面有示例,写的很清楚,可以去看一下,本文也会给出代码示例:
- 3.1 selenium截取开启日志的代码如下:
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.0.3770.8起,就必须这样去运行了。
注意,只打开性能日志还是不能抓取body的,如果你的需求只是判断状态码,那么上面的解决方式已经足够了。
- 3.2 下面记录怎么让我们抓取到返回的消息体:
1、为什么需要获取requestid:
Chrome性能日志的获取需要配合Chrome DevTool的方法一起使用,这个文档详细列出了Chrome提供的domains,定位到domains——network下,可以选取需要的methods:https://chromedevtools.github.io/devtools-protocol/tot/Network/
在这个里面,我选到了自己需要的方法,如下图,可以看到,这里需要传入一个参数,叫做requestId,它是唯一的请求ID,获得这个我们就能抓取到想要的body了。但是这个requestId真是听都没听过,要去从哪里获取呢?这时候就需要去分析一下我们抓取的性能日志里面的事件了。
2、 关于Chrome返回的日志事件,可以参加这个博客,里面有很详细介绍,我就是基于这个博客(https://blog.csdn.net/zhuyiquan/article/details/80148767#networkrequestwillbesent。),分析出自己要用到的事件的——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进行解析即可。就在我信心满满的时候,现实又给了沉重的一击,在抓取请求的body过程中,程序报错
No resource with given identifier found
这是踩得最大的坑,整整困扰了我五六个小时,以为是自己代码哪里处理的有问题,一直在调试,在网上搜索问题,最后在一个不太相关的关于js的博客里面,看到这么一句话:getResponseBody will error occur when the query returns nothing...
回头去界面手动获取了一下当前运行页面的ajax请求,果然都是没有返回体的请求ORZ。
果断上了try..except..,然后程序就华丽丽的运行起来了!此刻的心情真是又激动又想哭。
后记:
这种需求感觉还是很常见的,毕竟界面元素能否加载成功,看接口返回是最直接最可靠的方法,但是不知道为什么国内好像没有相关的博客(也可能是我手残没有搜到),所以谨以此文做记录,希望有需要的小伙伴不要走我这么多弯路,能够轻轻松松解决问题~~
PS:当时在翻墙的过程中,也搜到了一种解决方法是升级selenium至4,因为selenium 4开始支持与Chrome DevTools 一起获取。但是搜到的只有Java示例,因为对于Java不是很熟悉,所以弃用,在这里一并提供给大家,有需要的可以自取:
https://medium.com/@ohanaadi/chrome-devtools-and-selenium-4-eadab5d755b7
-----------------------我是分割线2021/02/01---------------------------
今天翻阅技术博客的时候,发现了一个开源项目,是通过代理的手段截取的ajax请求,先记录一下资料:
https://github.com/lightbody/browsermob-proxy
利用selenium抓取网页的ajax请求的更多相关文章
- Python爬虫实战八之利用Selenium抓取淘宝匿名旺旺
更新 其实本文的初衷是为了获取淘宝的非匿名旺旺,在淘宝详情页的最下方有相关评论,含有非匿名旺旺号,快一年了淘宝都没有修复这个. 可就在今天,淘宝把所有的账号设置成了匿名显示,SO,获取非匿名旺旺号已经 ...
- 利用Crowbar抓取网页异步加载的内容 [Python俱乐部]
利用Crowbar抓取网页异步加载的内容 [Python俱乐部] 利用Crowbar抓取网页异步加载的内容 在做 Web 信息提取.数据挖掘的过程中,一个关键步骤就是网页源代码的获取.但是出于各种原因 ...
- 利用page_source抓取网页中的URL,进行链接测试
selenium的page_source方法可以获取到页面源码,下面就把它应用到链接测试中. # coding:utf-8 __author__ = 'helen' import re,request ...
- 我的第一个爬虫程序:利用Python抓取网页上的信息
题外话 我第一次听说Python是在大二的时候,那个时候C语言都没有学好,于是就没有心思学其他的编程语言.现在,我的毕业设计要用到爬虫技术,在网上搜索了一下,Python语言在爬虫技术这方面获得一致好 ...
- 利用jsoup抓取网页图片
jsoup简介 jsoup is a Java library for working with real-world HTML. It provides a very convenient API ...
- 利用Selenium爬取淘宝商品信息
一. Selenium和PhantomJS介绍 Selenium是一个用于Web应用程序测试的工具,Selenium直接运行在浏览器中,就像真正的用户在操作一样.由于这个性质,Selenium也是一 ...
- selenium抓取动态网页数据
1.selenium抓取动态网页数据基础介绍 1.1 什么是AJAX AJAX(Asynchronouse JavaScript And XML:异步JavaScript和XML)通过在后台与服务器进 ...
- PHP利用Curl实现多线程抓取网页和下载文件
PHP 利用 Curl 可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,然而因为php语言本身不支持多线程,所以开发爬虫程序效率并不高,一般采集 数据可以利用 PHPquery ...
- 使用selenium webdriver+beautifulsoup+跳转frame,实现模拟点击网页下一页按钮,抓取网页数据
记录一次快速实现的python爬虫,想要抓取中财网数据引擎的新三板板块下面所有股票的公司档案,网址为http://data.cfi.cn/data_ndkA0A1934A1935A1986A1995. ...
随机推荐
- swing桌面四子棋程序开发过程中遇到的一些问题记录(二)
第二个遇到的问题是将JButton按钮设置成透明的按钮.首先UI给我一张透明的图片,如果我直接给Button按钮设置背景图片的话,是没有透明的效果的,只会留下白色的底,设置前后的效果如下图 制作透明的 ...
- (数据科学学习手札102)Python+Dash快速web应用开发——基础概念篇
本文示例代码与数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的新系列教程Python+Dash快 ...
- 软件性能测试分析与调优实践之路-Web中间件的性能分析与调优总结
本文主要阐述软件性能测试中的一些调优思想和技术,节选自作者新书<软件性能测试分析与调优实践之路>部分章节归纳. 在国内互联网公司中,Web中间件用的最多的就是Apache和Nginx这两款 ...
- Popup中ListBox的SelectChange事件关闭弹出窗体后主窗体点击无效BUG
WPF的BUG!弹出框的 自定义控件里有Popup, Popup里面放一个ListBox 在ListBox中的SelectionChange事件触发关闭弹出框后,主窗体存在一定概率卡死(但点击标题又能 ...
- C中的dll 、lib和exe文件
参考:链接1 链接2 DLL 动态链接库(Dynamic Link Library,缩写为DLL),运行时加载是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源.动态链接 ...
- 【高级排序算法】1、归并排序法 - Merge Sort
归并排序法 - Merge Sort 文章目录 归并排序法 - Merge Sort nlogn 比 n^2 快多少? 归并排序设计思想 时间.空间复杂度 归并排序图解 归并排序描述 归并排序小结 参 ...
- [Usaco2006 Nov]Corn Fields牧场的安排
题目描述 Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M<=12; 1<=N<=12),每一格都是一块正方形的土地.FJ打算在牧场上的某几格土 ...
- IP2723T中文规格书PDF
IP2723T 是一款集成多种协议.用于 USB 输出端口的快充协议 IC.支持多种快充协议,包括 USBTypeC DFP,PD2.0/PD3.0/PPS,HVDCPQC4/QC4+/QC3.0/Q ...
- uni-app开发经验分享七: 有关列表数据下拉加载方法的解析及记录
在使用uni.request获取后台数据时,我们往往碰到一个问题,列表的懒加载及数据实时更新,这里记录下我制作这类功能的方法. 问题描述:后台返回数据,前端需要进行10个为一组来分页,先显示前10个, ...
- CSS响应式布局学习笔记(多种方法解决响应式问题)
在做web开发的工作中,会遇到需要我给页面根据设计的要求,进行响应式布局,这里跟大家分享下我对于响应式布局的解决方法: 我主要利用的是CSS3 媒体查询,即media queries,可以针对不同的媒 ...