当前位置: 首页 > news >正文

chromedp 笔记

📚 一、XPath 核心内置函数(基于 XPath 1.0,主流浏览器支持)
1. ​​节点集函数​​
count(node-set):返回节点数量(如 count(//div) 统计所有 <div> 数量)
position():返回当前节点在上下文中的位置(如 //li[position()=1] 定位第一个 <li>)
last():返回节点集中最后一个节点的位置(如 //tr[last()] 选中表格最后一行)
2. ​​字符串处理函数​​
contains(string1, string2):判断是否包含子串(如 //a[contains(@href, 'example')])
starts-with(string1, string2):检查字符串开头(如 //input[starts-with(@id, 'user_')])
substring(string, start, length):截取子串(如 substring('Hello', 1, 3) → "ell")
normalize-space(string):去除首尾空格并合并连续空格(如 //div[normalize-space(text())='登录'])
concat(string1, string2, ...):拼接字符串(如 concat('ID-', @id))
3. ​​布尔逻辑函数​​
not(boolean):逻辑取反(如 //input[not(@disabled)] 排除禁用输入框)
true() / false():返回布尔常量
4. ​​数值运算函数​​
sum(node-set):对节点值求和(如 sum(//span[@class='price']) 计算总价)
floor(number) / ceiling(number):向下/向上取整(如 floor(3.7) → 3)
round(number):四舍五入
🧩 二、高阶函数(XPath 2.0+,部分场景需工具支持)
matches(string, pattern):正则表达式匹配(如 //*[matches(@id, '^section\d+$')])
ends-with(string1, string2):检查字符串结尾(需 XPath 2.0 支持)
tokenize(string, separator):按分隔符拆分字符串
🎯 三、XPath 匹配教程推荐(从入门到精通)
1. ​​基础语法与实战​​
​​MDN XPath 文档​​:权威标准函数库说明,覆盖全部核心函数语法及示例 。
​​《UI自动化测试中XPath定位的终极指南》​​:
含轴定位(following::、preceding-sibling::)、动态加载处理、跨 iframe 定位等高级技巧。
优化建议:避免冗长路径,优先用 CSS Selector 提升性能。
2. ​​函数深度解析​​
​​《【Xpath合集】函数与操作符详解》​​:
结合影刀 RPA 案例,演示 contains() 匹配动态文本、count() 统计元素数量等场景。
附练习题与 HTML 结构,适合动手实践(如定位多 class 元素、排除隐藏元素)。
3. ​​爬虫专项教程​​
​​《Python3爬虫:使用XPath解析数据(27种典型用法)》​​:
覆盖节点关系(父子、兄弟)、属性提取(@href)、文本捕获(text())等爬虫高频需求。
提供 lxml 库操作代码示例(如修正 HTML 结构、分步定位调试)。
4. ​​避坑指南​​
​​《XPath定位实用技巧》​​:
解决动态属性、嵌套文本、不可见元素等疑难问题(如 //div[not(contains(@class,'hidden'))])。
调试技巧:浏览器控制台用 $x("//div") 验证表达式。
💎 总结:函数使用场景对比
​​场景​​    ​​推荐函数​​    ​​示例​​
动态 ID 匹配    starts-with(), contains()    //button[starts-with(@id, 'btn_')]
多 class 元素筛选    contains() + 空格边界模拟    //div[contains(concat(' ', @class, ' '), ' btn ')]
文本精准提取    normalize-space()    //span[normalize-space()='提交']
表格数据汇总    sum(), position()    sum(//td[@class='price'])
条件排除    not()    //input[not(@disabled)]

🧩 ​​1. //input[not(@disabled)] 的作用​​
​​核心功能​​:此表达式会匹配所有 ​​不包含 disabled 属性​​ 的 <input> 元素。
​​是否排除 disabled="true"?​​
✅ ​​是的​​。无论 disabled 属性的值是 true、false 还是空值(如 disabled="" 或 disabled),只要该属性存在,都会被 not(@disabled) 排除。
例如:
<input disabled>(无值)
<input disabled="true">
<input disabled="disabled">
均会被排除。
⚙️ ​​2. disabled 属性的值是否加引号的区别​​
​​加引号与否不影响禁用效果​​:
HTML 中 disabled 是布尔属性,只要存在即生效,无论值是什么(包括空值或任意字符串)。以下写法效果相同:
<input disabled>          <!-- 生效,输入框被禁用 -->
<input disabled="true">    <!-- 生效,输入框被禁用 -->
<input disabled="false">   <!-- 生效!值"false"无效,属性存在即禁用 -->
<input disabled="">        <!-- 生效,空值仍被识别为禁用 -->

readonly属性也类似,都是布尔类型,存在即禁止


对于xpath选择器来说,标签里面的所有都是属性,都通过//tag[@attr="value"]来匹配;或者//tag[contains(@attr, "value")], =等于号需要完全匹配,contains包含即可
chromedp.Click(`//button[contains(@class,"submit") and text()="确认"]`, chromedp.BySearch)

而对于css/js选择器,id和class属于专有属性,有自己的标识,#表示id, .表示class:
chromedp.Click(`#form-container > button.submit`, chromedp.ByQuery)

Chromedp支持的选择器类型​​
​​选择器类型​​    ​​    常量名称​​    ​​        使用示例​​    ​​                                                    适用场景​​
​​CSS选择器​​        chromedp.ByQuery    chromedp.Click("button.submit", chromedp.ByQuery)                常规元素定位,语法简洁,定位class包含submit的button按钮
​​XPath​​            chromedp.BySearch    chromedp.Click(//button[text()="Submit"], chromedp.BySearch)    复杂层级关系或属性匹配,定位<button>submit</submit>
​​JS路径​​            chromedp.ByJSPath    chromedp.OuterHTML("document.body", &html, chromedp.ByJSPath)    通过JavaScript表达式定位元素
​​ID​​                chromedp.ByID        chromedp.WaitVisible("#username", chromedp.ByID)                快速定位具有唯一ID的元素
​​节点ID(底层)​​    chromedp.ByNodeID    需结合DevTools协议,较少直接使用                                高级调试或底层操作

​​注​​:若不显式指定 By* 常量,Chromedp ​​默认使用 ByQuery(即CSS选择器)​​。


除OuterHTML(包含标签本身)和InnerHTML(标签子元素,不含标签本身)外,chromedp提供多种内容提取方式:

​​chromedp.Text(selector, &result)​​
​​功能​​:提取元素的纯文本(忽略所有HTML标签)
​​示例​​:
var text string
chromedp.Text("#title", &text) // 获取id="title"元素的文本

​​chromedp.Value(selector, &result)​​
​​功能​​:获取表单元素(如<input>、<textarea>)的值
​​示例​​:
var inputVal string
chromedp.Value("#search-box", &inputVal)

​​chromedp.AttributeValue(selector, attrName, &value, &exists)​​
​​功能​​:提取元素的特定属性值(如href、src)
​​示例​​:
var link string
chromedp.AttributeValue("a#home", "href", &link, nil)

​​chromedp.Evaluate(jsExpr, &result)​​
​​功能​​:执行JavaScript表达式并返回结果(支持复杂逻辑)
​​示例​​:
var width float64
chromedp.Evaluate(`window.innerWidth`, &width)

🛠️ 三、​​chromedp中的高级DOM操作​​
通过Chrome DevTools Protocol(CDP),chromedp支持更底层的DOM操作:

​​节点查询​​
chromedp.Query():通过选择器查找单个节点
chromedp.QueryAll():查找所有匹配节点
​​节点属性操作​​
chromedp.SetAttributeValue():动态修改属性
chromedp.RemoveAttribute():删除属性
​​样式获取​​
chromedp.ComputedStyle():提取元素计算后的CSS样式
​​节点结构操作​​
chromedp.RemoveNode():删除DOM节点
chromedp.InsertBefore():在指定位置插入节点
​​事件监听​​
chromedp.ListenTarget():监听DOM变更事件(如节点新增/删除)
chromedp.ListenTarget(ctx, func(ev interface{}) {
if ev, ok := ev.(*dom.ChildNodeInserted); ok {
log.Println("新增节点:", ev.Node.NodeName)
}
})

获取cookie
import "github.com/chromedp/cdproto/network"

func getCookies(ctx context.Context) ([]*network.Cookie, error) {
cookies, err := network.GetAllCookies().Do(ctx)
if err != nil {
return nil, err
}
return cookies, nil
}

// 在任务链中调用
var cookies []*network.Cookie
err := chromedp.Run(ctx,
chromedp.Navigate(targetURL),
chromedp.ActionFunc(func(ctx context.Context) error {
cookies, err = getCookies(ctx)
return err
}),
)

Chromedp被识别的风险​​
Chromedp默认特征可能被服务器拦截:

​​自动化标识​​:
navigator.webdriver属性为true。
请求头包含HeadlessChrome标识。

​​指纹特征​​:
固定窗口尺寸(无头模式默认800×600)。
缺少常见浏览器插件(如Flash、PDF Viewer)。

​​行为模式​​:
无鼠标移动轨迹或固定操作间隔。
无滚动行为模拟。


🛡️ ​​三、降低拦截的反爬措施​​
1. ​​基础伪装​​
​​措施​​    ​​实现方式​​    ​​效果​​
​​禁用自动化标志​​    chromedp.Flag("disable-blink-features", "AutomationControlled")    隐藏navigator.webdriver
​​随机化窗口尺寸​​    chromedp.WindowSize(1920+rand.Intn(200), 1080+rand.Intn(200))    模拟真实用户分辨率
​​修改语言指纹​​    chromedp.Flag("lang", "zh-CN,zh;q=0.9")    避免语言特征异常
​​注入JS修改Navigator​​    通过chromedp.Evaluate()覆盖plugins/languages属性    伪装插件和语言列表

2. ​​请求特征伪装​​
​​随机化请求头顺序​​:重排请求头字段(如Accept、User-Agent)的顺序。
​​添加伪装的Sec头​​:
req.Headers["Sec-Fetch-Dest"] = "document"
req.Headers["Sec-Fetch-Mode"] = "navigate"
​​使用动态User-Agent​​:轮换不同浏览器UA字符串。

3. ​​行为模式模拟​​
​​随机操作延迟​​:在关键步骤间添加随机休眠:
chromedp.Sleep(time.Duration(500+rand.Intn(1500)) * time.Millisecond)
​​模拟鼠标轨迹​​:通过input.DispatchMouseEvent生成人类移动轨迹。
​​滚动页面​​:触发懒加载并分散请求密度:
chromedp.Evaluate(`window.scrollBy(0, 500)`, nil)

4. ​​高级指纹对抗​​
对Canvas/WebGL等高级指纹进行动态修改:

chromedp.Evaluate(fmt.Sprintf(`
WebGLRenderingContext.prototype.getParameter = function(parameter) {
if (parameter === 37445) { // VENDOR
return '%s'; // 随机显卡厂商
}
return this.__proto__.getParameter(parameter);
};
`, randomVendor), nil)

err := chromedp.Run(ctx,
// 使用CSS选择器等待搜索框可见
chromedp.WaitVisible(`input[name="q"]`, chromedp.ByQuery),
// 使用XPath点击按钮
chromedp.Click(`//button[contains(@class, "submit-btn")]`, chromedp.BySearch),
// 使用JS路径获取页面标题
chromedp.Evaluate(`document.title`, &title, chromedp.ByJSPath),
)
if err != nil { ... }

func worker(tab *chromedp.Target) {
ctx := tab.CDPContext()  // 从标签页创建独立Context
chromedp.Run(ctx,
chromedp.Navigate("https://example.com"),
chromedp.WaitVisible("body"),
chromedp.Text("#title", &text),
)
}

func main() {
// 1. 初始化浏览器
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()

    var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// 创建独立标签页
tab, err := chromedp.NewTarget(ctx, "")
if err != nil {
log.Fatal(err)
}
worker(tab)
}()
}
wg.Wait()
}

///
package main

import (
"context"
"io/ioutil"
"log"
"github.com/chromedp/chromedp"
)

func main() {
// 1. 配置Headless参数
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.Flag("headless", true),
chromedp.Flag("disable-gpu", true),
chromedp.Flag("no-sandbox", true),
)
allocCtx, allocCancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer allocCancel()

    // 2. 创建浏览器上下文
ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()

    // 3. 执行任务链:导航→等待元素→截图
var buf []byte
err := chromedp.Run(ctx,
chromedp.Navigate("https://example.com"),
chromedp.WaitVisible("body", chromedp.ByQuery), // 等待body加载
chromedp.FullScreenshot(&buf, 90),               // 全屏截图(质量90%)
)
if err != nil {
log.Fatal(err)
}

    // 4. 保存截图
if err := ioutil.WriteFile("screenshot.png", buf, 0644); err != nil {
log.Fatal(err)
}
log.Println("截图保存成功!")
}


///
var htmlContent string
err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.WaitReady("body", chromedp.ByQuery), // 等待基础元素
chromedp.OuterHTML("html", &htmlContent),     // 获取完整HTML
)

///
err := chromedp.Run(ctx,
chromedp.Navigate("https://example.com/form-page"),
// 1. 等待表单加载后保存其HTML
chromedp.WaitVisible(`#form-container`, chromedp.ByID),
chromedp.OuterHTML(`#form-container`, &formHTML, chromedp.ByID),
// 2. 继续操作:填写并提交表单
chromedp.SendKeys(`#email`, "user@example.com", chromedp.ByID),
chromedp.Click(`#submit-btn`, chromedp.ByID),
// 3. 等待结果出现并获取文本
chromedp.WaitVisible(`.result-message`, chromedp.ByQuery),
chromedp.Text(`.result-message`, &resultText, chromedp.ByQuery),
)

///
chromedp.Run(ctx,
chromedp.ScrollIntoView(`img`, chromedp.ByQuery), // 滚动到图片位置
chromedp.Nodes(`img`, &nodes),
)

// 存储所有图片节点
"github.com/chromedp/cdproto/cdp"
var nodes []*cdp.Node
err := chromedp.Run(ctx,
chromedp.Navigate("https://example-news-site.com/article"),
chromedp.WaitVisible(`body`), // 等待页面加载
// 获取所有<img>标签
chromedp.Nodes(`img`, &nodes, chromedp.ByQueryAll),
)

方法一:手动遍历元组​​
将连续的奇偶索引分别作为 Name 和 Value:

func parseAttributes(attrs []string) map[string]string {
result := make(map[string]string)
for i := 0; i < len(attrs); i += 2 {
if i+1 < len(attrs) {
result[attrs[i]] = attrs[i+1]
}
}
return result
}

// 示例:获取节点的 class 属性
attrs := parseAttributes(node.Attributes)
class := attrs["class"]
​​方法二:使用 chromedp.Evaluate 执行 JS 获取​​
通过注入 JavaScript 直接获取结构化属性:

var attributes map[string]string
chromedp.EvaluateAsDevTools(`
const elem = document.querySelector("...");
const attrs = {};
for (const attr of elem.attributes) {
attrs[attr.name] = attr.value;
}
attrs;
`, &attributes)


安装浏览器:sudo apt-get install google-chrome-stable(Ubuntu/Debian)。
安装依赖库:如 libnss3、libxss1 等(避免启动失败):
sudo apt-get install -y libnss3 libxss1 libasound2 libgbm-dev
apt-get install -y google-chrome-stable 

常见问题解决​​
​​浏览器启动失败​​
​​依赖缺失​​:运行ldd $(which google-chrome)检查缺失库,通过apt安装。
​​权限问题​​:添加chromedp.Flag("no-sandbox", true)(仅限可信环境)。

package mainimport ("context""log""time""github.com/chromedp/cdproto/cdp""github.com/chromedp/chromedp""github.com/chromedp/chromedp/kb"
)func main() {// 禁用chrome headlessopts := append(chromedp.DefaultExecAllocatorOptions[:],chromedp.Flag("headless", false),chromedp.Flag("disable-gpu", true),chromedp.Flag("no-sandbox", true),chromedp.Flag("disable-plugins", true),chromedp.Flag("disable-blink-features", "AutomationControlled"),chromedp.Flag("ignore-certificate-errors", true),//chromedp.Flag("user-agent", userAgent),)allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)defer cancel()// create chrome instancectx, cancel := chromedp.NewContext(allocCtx,chromedp.WithLogf(log.Printf),)defer cancel()// create a timeout//ctx, cancel = context.WithTimeout(ctx, 5*time.Second)//defer cancel()// navigate to a page, wait for an element, clickvar example stringvar text stringvar nodes []*cdp.Nodesel := `//textarea[@aria-label="搜索"]`err := chromedp.Run(ctx,chromedp.Navigate(`https://www.google.com/search`),chromedp.WaitVisible(sel, chromedp.BySearch), // 等待搜索框chromedp.OuterHTML("body", &example),chromedp.Text("#title", &text, chromedp.ByQuery),chromedp.Nodes(`img`, &nodes, chromedp.ByQueryAll),//缓一缓chromedp.Sleep(2*time.Second),chromedp.SendKeys(sel, "chromedp"+kb.Enter, chromedp.BySearch),)if err != nil {log.Fatal(err)}log.Printf("Go's time.After example:\n%s", example)time.Sleep(time.Minute)
}
常用的几个方法:chromedp.NewContext() 初始化chromedp的上下文,后续这个页面都使用这个上下文进行操作chromedp.Run() 运行一个chrome的一系列操作chromedp.Navigate() 将浏览器导航到某个页面chromedp.WaitVisible() 等候某个元素可见,再继续执行。chromedp.Value() 获取某个元素的value值chromedp.ActionFunc() 再当前页面执行某些自定义函数chromedp.OuterHTML() 获取元素的outer htmlchromedp.InnerHTML() 获取元素的inner htmlchromedp.Text() 读取某个元素的text值chromedp.Nodes() 根据xpath获取某些元素,并存储进入数组chromedp.Evaluate() 执行某个js,相当于控制台输入jsnetwork.SetExtraHTTPHeaders() 截取请求,额外增加header头chromedp.SendKeys() 模拟键盘操作,输入字符chromedp.Screenshot() 根据某个元素截图page.CaptureScreenshot() 截取整个页面的元素chromedp.Click() 模拟鼠标点击某个元素chromedp.Submit() 提交某个表单chromedp.WaitNotPresent() 等候某个元素不存在


http://www.dtcms.com/a/316358.html

相关文章:

  • 同向双指针——滑动窗口
  • 使用公众号的消息模板给关注用户发消息
  • UNet改进(30):SageAttention在UNet中的4-Bit量化实现详解
  • UOS20操作系统关闭NUMA和透明大页(UOS20+KunPeng920)
  • mq_timedreceive系统调用及示例
  • 工业设备远程监控的 “颠覆性突破”:边缘计算网关让千里之外如在眼前
  • 【图像算法 - 09】基于深度学习的烟雾检测:从算法原理到工程实现,完整实战指南
  • 16核32G硬件服务器租用需要多少钱
  • 【Redis初阶】------单线程模型
  • Next.js SSR 实战:构建高性能新闻网站
  • C++中的泛型算法(三)
  • 智慧城市SaaS平台|市容环卫管理系统
  • 【PHP】对数据库操作:获取数据表,导出数据结构,根据条件生成SQL语句,根据条件导出SQL文件
  • nordic通过j-link rtt viewer打印日志
  • Unknown initial character set index ‘255’,Kettle连接MySQL数据库常见错误及解决方案大全
  • 心念之球:在意识的天空下
  • Gemini CLI最近更新
  • GitLab:一站式 DevOps 平台的全方位解析
  • 笔记学习杂记
  • fastgpt本地运行起来的 服务配置
  • iptables 里INPUT、OUTPUT、FORWARD 三个链(Chain)详解
  • 编程算法:技术创新与业务增长的核心引擎
  • 如何在虚拟机(Linux)安装Qt5.15.2
  • STM32 外设驱动模块一:LED 模块
  • 第13届蓝桥杯Scratch_选拔赛_初级组_真题2021年10月23日
  • 基于MATLAB实现的频域模态参数识别方法
  • SpringAI:AI基本概念
  • 基于ARM+FPGA多通道超声信号采集与传输系统设计
  • PCIe Base Specification解析(六)
  • 五、逐波限流保护电路-硬件部分