利用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. ...
随机推荐
- C语言-表达式和运算符
表达式:表达式是c语言的主体,在c语言中,表达式由操作符和操作数组成.简单的表达式可以只有一个操作数.根据操作符的个数,可以将表达式分为简单表达式和复杂表达式,简单的表达式只含有一个操作符(如:5+5 ...
- Flask 操作Mysql数据库 - flask-sqlalchemy扩展
数据库的设置 Web应用中普遍使用的是关系模型的数据库,关系型数据库把所有的数据都存储在表中,表用来给应用的实体建模,表的列数是固定的,行数是可变的.它使用结构化的查询语言.关系型数据库的列定义了表中 ...
- idea或者java远程提交spark任务到yarn,Exception1
spark通過idea远程提交job到yarn: Caused by: java.lang.ClassCastException: cannot assign instance of scala.co ...
- Lambda获取类属性的名字
using System; using System.ComponentModel; using System.Linq.Expressions; using System.Reflection; p ...
- 查找linux系统下的端口被占用进程的两种方法 【转】
在linux下开发时,你的软件可能要使用某一个端口,或者想查找某一个端口是否被占用.需要怎么做呢??这的确是一个比较烦恼的问题,我也此为这个苦恼过.但是通过查找man手册,还是同事的交流.总结出来两种 ...
- ASP.NET Core - JWT认证实现
一.JWT结构 JWT介绍就太多了,这里主要关注下Jwt的结构. Jwt中包含三个部分:Header(头部).Payload(负载).Signature(签名) Header:描述 JWT 的元数据的 ...
- 【Spring】Spring中的Bean - 1、Baen配置
Bean配置 简单记录-Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)-Spring中的Bean 什么是Spring中的Bean? Spring可以被看作是一个 ...
- 【Linux】fdisk -l发现有加号"+"
今天分区不够了,打算扩下分区,想起当时创建机器的时候还有大约80多个G没有用,今天打算重新利用上 就用了fdisk /dev/sda 创建了两个分区,但是发现分区下面有加号,感到而别的困惑 最后在很多 ...
- LTH7锂电池充放电IC完整方案
内容目录: A,LTH7贴片5脚充电芯片 PW4054 1, 单节的锂电池保护电路 单节为3.7V锂电池(也叫4.2V)和3.8V锂电池(也叫4.35V) 2, 单节的锂电池充电电路 ...
- IOC技术在前端项目中的应用
目录 背景 什么是IOC 如何实现一个IOC 第一步:实现一个容器 第二步:用好装饰器 第三步:使用容器 扩展和展望 最后 背景 前端发展至今已经过去30余年,前端应用领域在不断壮大的过程中,也变得越 ...