- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
Selenium 是一款开源且可移植的自动化软件测试工具,专门用于测试网页端应用程序或者采集网页端数据。它能够在不同的浏览器和操作系统上运行,具有很强的跨平台能力。Selenium可以帮助测试人员更高效地自动化测试基于Web网页端的应用程序,也可以帮忙开发者方便地完成网页端数据的采集工作.
Chrome Dev Tools 是直接内置于 Chrome 浏览器中的调试工具。它为开发人员提供了一整套用于检查、调试、分析和优化 Web 网页端应用程序的工具。下面举例讲述 Chrome Dev Tools 支持的一些功能:
元素选项卡可以显示当前页面的 DOM 树,使用者也可以通过该功能实时修改当前页面的 DOM 树。举例来讲,我们现在想修改百度搜索按钮背景颜色成红色,我们就可以通过元素选项卡来完成。我们在元素选项卡中选中搜索框的按钮并且将 background-color 样式设置为红色即可,下方截图是实现的效果.
控制台选项卡类似于交互式的终端,我们可以在这里看到JavaScript代码打印的日志信息,方便我们定位问题,也可以在这里输入 JavaScript 代码,并且可以让这些代码实时生效,甚至改变原有网页的行为。例如,我们打开某个网站的登录页面并且在控制台选项卡中输入如下的代码:
document.querySelector('button').addEventListener('click', function(){
alert("login button is clicked");
});
通过网页中注入上面的代码,我们可以监控到该页面上面所有 button 元素的点击操作,当用户点击登录按钮的时候就会弹窗显示消息“login button is clicked”。具体情形如下图所示:
源代码选项卡可以查看完整的网页源代码,对源代码进行单步调试,观察代码的调用堆栈,也可以动态修改代码变量。为了能够更加清晰地说明源代码选项卡的作用,我简单编写了一个 HTML 页面。其内容如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>example page 1</title>
</head>
<body>
<input type = "button" value = "点击我" onclick = "hello('World')" />
<script>
function hello(name) {
let phrase = `Hello, ${name}!`;
say(phrase);
}
function say(phrase) {
alert(phrase);
}
</script>
</body>
</html>
首先,我们在 Chrome 浏览器中打开上面的网页内容,进入到开发者工具,切换到源代码选项卡,我们会看到下面的视图: 如上图所示,源代码选项卡主要由3个部分组成:
文件导航窗口:文件导航窗口中列举了整个网页相关的文件列表和路径,主要包括:HTML,JavaScript,CSS 和浏览器扩展插件等.
代码编辑窗口:源代码选项卡的第二个窗口是一个源代码编辑器,我们可以在这里查看和编辑各个文件的源代码,也可以在这里设置调试断点.
调试信息窗口:调试信息窗口展示了当前设置的断点信息和调用堆栈信息等.
我们有两种方法可以给当前页面的代码设置断点.
设置断点的第一种方法是在代码编辑窗口中点击对应的行号设置断点。具体视图如下所示:
调试信息窗口中会展示我们设置的所有断点信息。除了设置普通的断点,我们还可以设置条件断点(Conditional Breakpoints)。现在,我们将上图中的第一个断点修改为条件断点,设置只有当 param 变量等于 World 的时候才会触发断点。设置后的效果如下图所示:
设置断点的第二种方式是直接在代码编辑窗口中插入 debugger 命令。具体效果如下图所示:
通过网络选项卡,我们可以观察到网络流量的情况以及网络的请求和响应。对于爬虫开发者来说,最感兴趣的内容应该是各个文件的具体请求和响应信息。通过网络选项卡,我们会看到浏览器实时发送和接收的每个请求。通过点击每个请求,我们可以可以访问请求和响应的具体信息,cookie 和耗时等.
Chrome DevTools Protocol(CDP)是一套用于与基于Chromium内核浏览器进行通信的 API。它允许开发者通过发送命令和接收事件来与浏览器进行交互,以实现自动化测试、性能分析、调试等功能。CDP 在自动化测试、前端开发和爬虫程序开发等很多领域都发挥着重要的作用.
Chrome 浏览器的开发者将 Chrome DevTools 的功能领域划分为大约50个,每个版本的浏览器支持的功能领域可能会有些许差异。具体的功能领域划分我们可以通过官方文档链接进行查询,https://chromedevtools.github.io/devtools-protocol/。打开浏览器的开发者工具,我们可以开启实验特性下的协议监视器(protocol monitor)功能来查看当前浏览器页面发送的所有 CDP 指令.
在 Selenium 4 框架中,提供了两种与 Chrome Devtools 进行交互的方法,分别是 DevTools.send 方法和 ChromiumDriver.executeCdpCommand 方法.
DevTools 是 Selenium 框架为 CDP 协议编写的一个封装类,它内置了部分 CDP 协议指令.
ChromiumDriver 对象中的 executeCdpCommand 方法则是根据 CDP 协议指令的定义采用更加原始的方式直接向 Chrome 浏览器内核发送 CDP 协议指令。两种发送指令方式的差异性如下图所示:
接下来,我们分别采用DevTools.send方法和ChromiumDriver.sendCdpCommand方法来发送CDP协议指令来展示Selenium与CDP协议是如何结合在一起使用的.
首先,我们来看一看如何使用 DevTools 对象来操作 CDP 协议指令。假设,我们在进行数据采集的时候,希望能够实时记录某一个网站针对特定 URL 的请求数据和响应数据。这个时候,我们可以利用 CDP 协议中的 Network 领域功能来跟踪页面的相关网络活动。要实现捕获网络请求和响应数据的功能,我们首先需要使用 Network.enable 方法来开启页面的网络活动追踪功能,然后监听 Network.requestWillBeSent 事件和 Network.responseReceived 事件。具体代码示例如下所示:
DevTools devTools = chromeDriver.getDevTools();
devTools.createSession();
devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
ThreadUtils.sleepQuietly(Duration.ofSeconds(5));
devTools.addListener(Network.responseReceived(), response -> {
if(response.getResponse().getUrl().contains("token") || response.getResponse().getUrl().contains("userinfo")) {
String url = response.getResponse().getUrl();
String responseBody = devTools.send(Network.getResponseBody(response.getRequestId())).getBody();
System.out.println(String.format("request url & response body: %s, %s", url, responseBody));
}
});
chromeDriver.get("https://www.cnblogs.com/");
执行上述代码之后,我们会得到如下所示的打印结果.
在第二个示例中,我们采用 executeCdpCommand 方法来直接发送 CDP 指令给浏览器内核。假设我们现在使用的是 v96 版本的 Chrome 浏览器,与该版本浏览器对应的 Selenium DevTools 包装类中并不支持 Page.printToPDF 的 CDP 协议指令,这样我们就不得不使用 executeCdpCommand 方法来直接发送 CDP 协议指令.
首先,我们打开链接:https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF,查看具体的 Page.printToPDF 指令定义.
了解完指令定义之后,我们就可以按照指令定义来编写相关代码,具体代码示例如下所示:
chromeDriver.get("https://www.cnblogs.com/");
Thread.sleep(3000);
Map<String, Object> params = Maps.newHashMap();
params.put("displayHeaderFooter", true);
params.put("paperWidth", 11.0f);
params.put("headerTemplate", "<div style= \"font-size: 8px;\"> <span class=\"url\"></span></div>");
Map<String, Object> response = chromeDriver.executeCdpCommand("Page.printToPDF", params);
Path destination = Paths.get("fullpage-screenshot-chrome.pdf");
Files.write(destination, Base64.getDecoder().decode(response.get("data").toString()));
chromeDriver.quit();
上述代码执行之后,我们会得到一个 PDF 文件.
本文介绍了有关 Chrome DevTools,Chrome DevTools Protocol 以及 Selenium 与 CDP 协议结合应用的一些基本知识。希望它可以您在编写自动化爬取/采集程序的时候帮助到您.
另外,更多有关网络数据采集\爬取、验证码识别和逆向分析等相关知识,可以阅读我最近出版的《Java网络爬虫精解与实践》一书,该书知识结构紧凑,内容覆盖全面.
另外,该书还提供了对应的网络数据采集训练平台:https://benshu.tech/crawler.
最后此篇关于CDP与Selenium相结合——玩转网页端自动化数据采集/爬取程序的文章就讲到这里了,如果你想了解更多关于CDP与Selenium相结合——玩转网页端自动化数据采集/爬取程序的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在字符串中有一个大词。例子白 Wine 额外优惠。 我想在第一行使用“White”,在第二行使用“wine extra offer”。使用下面的代码: string value="White win
我想在无符号中执行一些算术运算,需要取负整数的绝对值,比如 do_some_arithmetic_in_unsigned_mode(int some_signed_value) { unsign
我正在努力使用 data.table 来总结向量函数的结果,这在 ddply 中很容易。 问题 1:使用带有矢量输出的(昂贵的)函数聚合 dt dt[ , as.list(quantile(x)),
我有两个分数列表; 说 A = [ 1/212, 5/212, 3/212, ... ] 和 B = [ 4/143, 7/143, 2/143, ... ] . 如果我们定义 A' = a[0] *
我已经使用 numpy 从 csv 文件中获取数据。 numpy 数组的尺寸为:100*20。我如何取列的平均值(比如 col 3,5,8)并用包含这 3 个 cols 平均值的新列替换它们 如果
在 Rust 中取任意数的 n 次根的最佳方法是什么?例如,num crate 只允许取整数类型的第 n 个主根,即 floor'ed 或 ceil'ed 值......如何最好地接近实际值? 最佳答
看起来这应该很容易,但我很困惑。我已经掌握了使用 dplyr 进行编程的大致技巧0.7,但为此苦苦挣扎:How do Iprogram in dplyr我想要编程的变量是否是一个字符串? 我正在抓取数
在 Rust 中取任意数的 n 次根的最佳方法是什么?例如,num crate 只允许取整数类型的第 n 个主根,即 floor'ed 或 ceil'ed 值......如何最好地接近实际值? 最佳答
我有一个 pandas 数据框,其中有一列名为“coverage”。对于一系列特定索引值,我想获取前 100 行的平均“覆盖率”值。例如,对于索引位置 1001,我想要第 901-1000 行的平均“
import pandas as pd data = {'date': ['1998-03-01', '2001-04-01','1998-06-01','2001-08-01','2001-05-0
我有一个包含 100 个数字的 NSArray。我想创建一个 5 个数字的 NSArray。第二个数组中的第一个数字是第一个数组中前 20 个数字的平均值。第二个数字是第一个数组中第二组 20 个数字
我该怎么做?我试过 abs() 但它只适用于整数。有内置的方法吗? CGFloat flo = -123; abs(flo) 返回 0 最佳答案 使用 fabs() CGFloat f = -123.
我正在采用以下计算的 log2: tl_out.a.bits.size := log2Ceil(s1_row * s2_column * 4.U) 其中,s1_row 和 s2_column 是 UI
如何从 m 个元素集合中取出 n 个元素,以便在元素用完时从头开始? List list = new List() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; List newL
我已经完成了研究,但似乎找不到有关该主题的足够文档。 在 Object streams 上尝试一些代码时,我注意到将 BufferedOutputStream 放入 ObjectOutputStrea
我需要计算数据中连续时间组之间的差异,如下所示 from io import StringIO import pandas as pd strio = StringIO("""\
我在 Mongo 数据库中有以下文档: { _id: 1, question: "Blue or red?", __v: 0, votes: [9, 5] } 我想在后
好吧,宇宙中一定有人知道这个问题的答案。 我已经在这里问过这个问题,但仍然没有解决方案。 我需要保留和换行 div 中的文本。到目前为止,我很难想出解决方案。我找到的最佳解决方案并不适用于所有浏览器。
我正在尝试采用 3 个单独的整数输入(年、月、日)并采用这 3 个条目并从中形成一个日期对象,以便我可以使用它来比较其他日期。 这是我目前所拥有的,不知从何而来: public void compar
在我的 IOS 项目中,我有一个包含该函数的自定义 Logger 类(单例) - (void)log:(NSString *)domain logLevel:(int)level logMessage
我是一名优秀的程序员,十分优秀!