网站模板预览做素材网站如何赚钱

张小明 2026/1/3 4:04:35
网站模板预览,做素材网站如何赚钱,宁波企业网站开发公司,网页设计教程书籍推荐前言#xff1a; 如果你做过爬虫或浏览器自动化#xff0c;大概率用过 Selenium。它很强大#xff0c;但也有痛点#xff1a;启动慢、资源占用高、操作容易被反爬检测。后来 DrissionPage 横空出世#xff0c;直接用 CDP 协议控制浏览器#xff0c;性能和灵活性都上了一…前言如果你做过爬虫或浏览器自动化大概率用过 Selenium。它很强大但也有痛点启动慢、资源占用高、操作容易被反爬检测。后来 DrissionPage 横空出世直接用 CDP 协议控制浏览器性能和灵活性都上了一个台阶。我用 DrissionPage 做了不少项目但每次遇到问题去翻源码时总觉得雾里看花。与其被动地用不如主动地造一次。于是打算从头研究一下项目源码整理一下。同时也缓冲一下之前的旧坑。什么是cdp1. CDP 的本质JSON-RPC over WebSocketCDP 并不是什么魔法它本质上就是一堆 JSON 数据包在 WebSocket 上发来发去。当打开 Chrome 浏览器的F12 开发者工具时那个“开发者工具窗口”其实就是一个用 HTML/JS 写的前端网页。当点击“Console”选项卡时工具发送了一条 CDP 命令给浏览器内核。当点击“Network”查看抓包时浏览器内核通过 CDP 把请求数据推送到工具界面。通信过程示例假设你想让浏览器跳转到百度你的程序客户端会通过 WebSocket 发送这样一段 JSON{ id: 1, method: Page.navigate, params: { url: https://www.baidu.com } }浏览器服务端收到后执行跳转然后回传{ id: 1, result: { frameId: A1B2C3... } } //这个frameid 在2. CDP 能做什么远超简单的 JSCDP 把浏览器能力划分为不同的Domains (域)主要有Runtime 域: 在页面上下文中执行 JS 代码Runtime.evaluate。反检测用途: 可以在页面加载前注入 JSPage.addScriptToEvaluateOnNewDocument用来覆盖 navigator.webdriver。Network 域: 拦截、修改、阻断网络请求。反检测用途: 可以拦截浏览器发出的指纹请求替换掉 Header 或者返回假数据。Page 域: 控制页面加载、截图、打印 PDF。DOM 域: 直接获取 DOM 树修改节点不经过 JS直接改内核数据。Debugger 域: 设置断点。这就是为什么爬虫可以逆向调试 JS。Emulation 域:关键功能: 它可以模拟移动端、修改 User-Agent、修改时区、修改地理位置。这对于通过环境检测非常有用。3. CDP 与 Puppeteer / Playwright 的关系Puppeteer 或 Playwright它们其实就是CDP 的封装库。Chromium: 提供 CDP 接口服务端。Puppeteer (Node.js): 帮你把 browser.newPage() 这种好写的代码翻译成底层的 Target.createTarget JSON 命令并通过 WebSocket 发给 Chromium。webdriver和cdp1. WebDriver 与 WebKit 的关系WebDriver 是什么它是“翻译官”WebDriver 是一个 W3C 定义的标准接口协议。就像 USB 接口一样标准是统一的但插入的设备浏览器不同就需要不同的驱动程序。谷歌 Chrome: 对应 chromedriver微软 Edge: 对应 msedgedriver火狐 Firefox: 对应 geckodriver苹果 Safari: 对应 safaridriverhttps://github.com/LoseNine/AutoWK的 WebKit: 对应 WebDriver.exe (这是一个专门为 WebKit 内核编译的驱动)autowk部分源码import http.client import subprocess import os import psutil import json def get_bin_file_path(filename): current_dir os.path.dirname(os.path.abspath(__file__)) exe_path os.path.join(current_dir, ., bin, filename) exe_path os.path.abspath(exe_path) return exe_path class AutoWKBase: def __init__(self, host, port,webkit_pathNone,webdriver_batNone): self.host host self.port port self.headers {Content-Type: application/json} self.session_id None self.conn None if not webkit_path and not webdriver_bat: self.webkit_path get_bin_file_path(MiniBrowser.exe) self.webdriver_bat get_bin_file_path(WebDriver.exe) #用於關閉引導頁 self.closePagefilefile:///get_bin_file_path(closePage.html) self.minibrowseraddr f{self.host}:{self.port 1} def launch_webkit(self,x0,y0,width10,height10,langen-US,timezoneAmerica/Chicago, proxyType,proxyHost,proxyPort,proxyUsername,proxyPassword, userDataDir,fpfile,userAgent,headlessFalse,enableListenFalse,networkListenPort0): env os.environ.copy() env[WEBKIT_INSPECTOR_SERVER] self.minibrowseraddr #给进行通信的窗口设置大小实际上启动完就可以关闭了 args [ self.webkit_path, f--x{x}, f--y{y}, f--width{width}, f--height{height}, f--lang{lang}, f--timezone{timezone}, f--url{self.closePagefile}, ] if proxyType and proxyHost and proxyPort: args.append(f--proxyType{proxyType}) args.append(f--proxyHost{proxyHost}) args.append(f--proxyPort{proxyPort}) if proxyUsername and proxyPassword: args.append(f--proxyUsername{proxyUsername}) args.append(f--proxyPassword{proxyPassword}) if userDataDir: args.append(f--userDataDir{userDataDir}) if fpfile: args.append(f--fpfile{fpfile}) if userAgent: args.append(f--userAgent{userAgent}) if headless: args.append(f--headless) if enableListen: args.append(f--enableListen) if networkListenPort: args.append(f--networkListenPort{networkListenPort}) self.webkit_process subprocess.Popen(args, envenv) def launch_webdriver(self): for proc in psutil.process_iter([name]): try: if proc.info[name] and WebDriver.exe in proc.info[name]: subprocess.run([taskkill, /f, /im, WebDriver.exe], stdoutsubprocess.DEVNULL) except (psutil.NoSuchProcess, psutil.AccessDenied): continue args [ self.webdriver_bat, f--target{self.minibrowseraddr}, f--port{str(self.port)}, ] self.webdriver_process subprocess.Popen(args) def connect(self): self.conn http.client.HTTPConnection(self.host, self.port) def request(self, method, endpoint, bodyNone): if body is None or body {}: body {capabilities: {firstMatch: [{}]}} self.conn.request(method, endpoint, bodyjson.dumps(body) if body else None, headersself.headers) return json.loads(self.conn.getresponse().read().decode(utf-8)) def create_session(self): result self.request(POST, /session) self.session_id result[value][sessionId] def delete_session(self): return self.request(DELETE, f/session/{self.session_id}) def close(self): print([INFO] Closing connection and shutting down MiniBrowser and WebDriver...) if self.conn: self.conn.close() for proc in psutil.process_iter([name]): try: if proc.info[name]: if MiniBrowser.exe in proc.info[name]: print(f[INFO] Terminating process: {proc.info[name]} (PID {proc.pid})) proc.terminate() if WebDriver.exe in proc.info[name]: print(f[INFO] Terminating process: {proc.info[name]} (PID {proc.pid})) subprocess.run([taskkill, /f, /im, WebDriver.exe], stdoutsubprocess.DEVNULL) except (psutil.NoSuchProcess, psutil.AccessDenied): continue print([INFO] autowk processes terminated.)这些 Driver 的作用就是接收 Python 发来的统一 HTTP 指令比如“点击”翻译成浏览器内部能听懂的私有指令。WebKit 是什么它是“发动机”WebKit 是一个浏览器排版引擎渲染引擎。它是浏览器的核心负责把 HTML/CSS 代码变成你屏幕上看到的图像。血缘关系Safari: 使用纯正的 WebKit 引擎。Chrome: 以前也用 WebKit后来 Google 觉得不爽把 WebKit 拿过来改了改起名叫Blink现在的 Chrome 内核其实是 WebKit 的一个分支。AutoWK / MiniBrowser: 这是一个基于纯 WebKit类似 Safari 内核编译出来的轻量级浏览器不是 Chrome。结论因为内核不同所以不能用 chromedriver 去控制 MiniBrowser必须用配套的 WebDriver.exe。2. 为什么说 Selenium “庞大”它依赖了什么前面展示的 AutoWK 代码非常“原生”它只用了 Python 自带的 http.client不需要安装任何第三方库。相比之下Selenium是一个重型框架。当 pip install selenium 时它不仅仅是下载了代码还引入了一套复杂的生态第三方依赖库urllib3: 处理 HTTP 连接池、重试等Selenium 不用 Python 自带的 http 库因为它太弱。trio / trio-websocket: Selenium 4 为了支持 CDP 和异步引入了这套庞大的异步 IO 库。certifi: 处理 SSL 证书。对象封装的开销在 AutoWK 里你发个 HTTP 请求就完了。在 Selenium 里你获取一个元素 ele driver.find_element(…)Selenium 会在内存里创建一个 WebElement 对象这个对象绑定了 session ID、parent ID 等各种属性。当你有成千上万个元素时这种封装就是一种负担。启动速度加载 selenium 库本身需要解析大量 Python 文件而 import http.client 几乎是瞬时的。3. 我能直接用 Python 调用 CDP 操作浏览器吗答案是绝对可以而且这是目前最高级的玩法。只要你的 Python 能发 WebSocket 数据包你就能控制 Chrome/Edge/CEF。如何实现你需要用到 websockets 这个库比 Selenium 轻量得多pip install websockets或者直接用 socket 手撸。极简代码示例直接控制 Chrome首先启动 Chrome 并开启调试端口chrome.exe --remote-debugging-port9222然后用 Python 控制它import asyncio import websockets import json import requests async def control_chrome(): # 1. 获取 WebSocket 调试地址 # Chrome 会在 http://127.0.0.1:9222/json 暴露当前页面的 WebSocket URL response requests.get(http://127.0.0.1:9222/json) pages response.json() # 拿到第一个标签页的 WebSocket 地址 ws_url pages[0][webSocketDebuggerUrl] print(fConnecting to: {ws_url}) # 2. 建立 WebSocket 连接 async with websockets.connect(ws_url) as ws: # 3. 发送 CDP 命令跳转到百度 # 每一个命令都有唯一的 idmethod 是 CDP 的方法名 command { id: 1, method: Page.navigate, params: { url: https://www.baidu.com } } await ws.send(json.dumps(command)) # 4. 接收结果 result await ws.recv() print(fReceive: {result}) # 5. 发送 CDP 命令执行 JS 获取 UserAgent js_command { id: 2, method: Runtime.evaluate, params: { expression: navigator.userAgent } } await ws.send(json.dumps(js_command)) result await ws.recv() print(fJS Result: {result}) # 运行 asyncio.get_event_loop().run_until_complete(control_chrome())这种方式的优缺点优点无敌轻量没有 Selenium没有 Driver只有 WebSocket。权限最高你可以调用 CDP 的所有隐藏功能改指纹、拦截网络、模拟地理位置。反检测强因为没有 webdriver 属性注入。缺点代码难写你需要自己管理 JSON 里的 id自己处理异步回调。维护累CDP 协议有时候会变没有库帮你屏蔽差异。CDPChrome DevTools Protocol底层架构1. 启动流程# 启动 Chrome 并开启远程调试chrome --remote-debugging-port9222--headless# 输出类似# DevTools listening on ws://127.0.0.1:9222/devtools/browser/xxx关键点Chrome 内部启动了一个WebSocket Server端口 9222 监听外部连接不需要安装任何驱动如 chromedriver直接和浏览器通信2. 通信协议两层架构┌──────────────────────────────────────────────────────┐ │ Python / Node.js 客户端 │ │ (DrissionPage, Puppeteer, etc.) │ └───────────────────┬──────────────────────────────────┘ │ │ ① HTTP 获取 Tab 列表 │ GET http://localhost:9222/json │ ▼ ┌──────────────────────────────────────────────────────┐ │ Chrome HTTP 服务器 │ │ 返回所有 Tab 的 WebSocket URL │ └───────────────────┬──────────────────────────────────┘ │ │ ② WebSocket 连接到具体 Tab │ ws://localhost:9222/devtools/page/xxx │ ▼ ┌──────────────────────────────────────────────────────┐ │ Chrome Tab (真实浏览器实例) │ │ - V8 引擎执行 JS │ │ - Blink 渲染引擎处理 DOM │ │ - 真实的 window/document/navigator │ └──────────────────────────────────────────────────────┘3. HTTP 层获取 Tab 信息# 访问 http://localhost:9222/jsoncurlhttp://localhost:9222/json# 返回 JSON所有打开的 Tab[{description:,devtoolsFrontendUrl:/devtools/inspector.html?wslocalhost:9222/devtools/page/XXX,id:E3F9F8C...,title:百度,type:page,url:https://www.baidu.com,webSocketDebuggerUrl:ws://localhost:9222/devtools/page/XXX← 关键}]所以这个可能会被反检测但是 获取列表的这个 HTTP 请求 是一个特征。 如果一个网站的 JavaScript 极其狡猾它可能尝试扫描本地端口虽然浏览器有 CORS 保护但在某些特定的网络配置或老版本浏览器下可能泄露 网页 JS 尝试请求 http://localhost:9222/json。 如果请求成功并返回了 JSON说明当前浏览器开启了远程调试端口。 结论用户是机器人/爬虫。关键点HTTP 负责总览当前 Tabs 信息每个 Tab 有唯一的webSocketDebuggerUrl客户端通过这个 URL 连接到具体的 Tab4. WebSocket 层执行命令Chrome DevTools 协议主要基于 JSON-RPC每个命令都是一个带有 id/method 和可选参数的 JavaScript 结构// 客户端发送命令通过 WebSocket{id:1,// 唯一 ID用于匹配响应method:Runtime.evaluate,// 命令执行 JSparams:{expression:document.title,// JS 代码returnByValue:true}}// Chrome 返回响应{id:1,// 对应请求的 IDresult:{result:{type:string,value:百度一下你就知道}}}关键点每个发送到 CDP 的命令必须有唯一的 ‘id’ 参数。消息响应将通过 WebSocket 传递并具有相同的 ‘id’没有 ‘id’ 参数的传入 WebSocket 消息是协议事件JS 在真实浏览器中执行不是模拟5. DrissionPage 的run_script()底层实现DrissionPage 源码分析简化版# DrissionPage 内部实现classChromiumPage:def__init__(self):# 连接到 Chromeself.wswebsocket.create_connection(ws://localhost:9222/devtools/page/XXX)self.msg_id0defrun_script(self,js_code):执行 JS 代码# 构建 CDP 命令msg{id:self.msg_id,method:Runtime.evaluate,# CDP 的 Runtime 域params:{expression:js_code,# 你的 JS 代码returnByValue:True,# 返回值而不是对象引用awaitPromise:True# 等待 Promise 完成}}# 发送到 Chromeself.ws.send(json.dumps(msg))self.msg_id1# 等待响应whileTrue:responsejson.loads(self.ws.recv())ifresponse.get(id)msg[id]:# 找到对应的响应returnresponse[result][result][value]实际流程fromDrissionPageimportChromiumPage pageChromiumPage()page.get(https://www.baidu.com)# 当你执行resultpage.run_script(navigator.userAgent)# 底层发生# 1. DrissionPage 通过 WebSocket 发送# {id: 1, method: Runtime.evaluate,# params: {expression: navigator.userAgent}}## 2. Chrome 在真实浏览器中执行 JS## 3. Chrome 返回# {id: 1, result: {result: {value: Mozilla/5.0...}}}## 4. DrissionPage 解析并返回结果6. CDP 的核心域DomainCDP 分为多个功能域常用的有Runtime 域执行 JS# Runtime.evaluate - 执行 JSpage.run_cdp(Runtime.evaluate,expression11)# Runtime.callFunctionOn - 调用对象方法page.run_cdp(Runtime.callFunctionOn,functionDeclarationfunction() { return this.title; },objectId...)Page 域页面控制# Page.navigate - 导航到 URLpage.run_cdp(Page.navigate,urlhttps://example.com)# Page.captureScreenshot - 截图page.run_cdp(Page.captureScreenshot)Network 域网络# Network.setCookies - 设置 Cookiepage.run_cdp(Network.setCookies,cookies[...])# Network.setExtraHTTPHeaders - 修改请求头page.run_cdp(Network.setExtraHTTPHeaders,headers{X-Custom:value})DOM 域DOM 操作# DOM.getDocument - 获取 DOM 树page.run_cdp(DOM.getDocument)# DOM.querySelector - 查询元素page.run_cdp(DOM.querySelector,nodeId1,selector#id)更多文章敬请关注gzh零基础爬虫第一天
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

汽车电商网站建设跨国浏览器

ComfyUI ControlNet Aux预处理模块数据格式错误排查与修复指南 【免费下载链接】comfyui_controlnet_aux 项目地址: https://gitcode.com/gh_mirrors/co/comfyui_controlnet_aux 你是否在使用ComfyUI ControlNet Aux进行图像预处理时,突然遭遇这样的困境&am…

张小明 2025/12/30 12:47:22 网站建设

网站推广公司秋长网站建设

Docker Swarm 和 Docker Compose 都是 Docker 官方提供的容器编排工具,但它们的应用场景和目标有所不同,它们的关系可以概括为:分工不同、可以结合使用。 1. 🎯 用途和范围的不同特性Docker ComposeDocker Swarm应用范围单主机/单…

张小明 2025/12/30 20:46:46 网站建设

网站建设是程序员吗wordpress 教育类主题

Hyper终端性能优化三阶段:从卡顿到丝滑的完整解决方案 【免费下载链接】hyper 项目地址: https://gitcode.com/gh_mirrors/hyp/hyper 你是否曾经在输入长命令时感受到明显的延迟?是否因为终端启动缓慢而错过重要的工作时机?作为开发者…

张小明 2025/12/30 12:57:34 网站建设

开网站做网站赚钱吗广州市越秀区建设局官方网站

5分钟快速上手:Windows轻量级倒计时神器Hourglass完全使用手册 【免费下载链接】hourglass The simple countdown timer for Windows. 项目地址: https://gitcode.com/gh_mirrors/ho/hourglass 还在为Windows系统缺乏专业计时功能而苦恼吗?Hourgl…

张小明 2025/12/30 12:19:48 网站建设

凡科的网站怎么仿在线教育网站平台建设的意义

在本地 RAG 系统中使用 Marker:高精度 PDF 到 Markdown 的离线开源解决方案(2025 更新) 在本地 RAG(Retrieval-Augmented Generation)系统中,PDF 解析质量是决定最终问答准确率的关键(Garbage …

张小明 2026/1/2 23:59:18 网站建设

正规网站制作全包盐城代运营

基于用户权限动态生成可访问知识图谱视图 在企业知识管理的智能化浪潮中,一个日益突出的问题摆在架构师面前:如何让AI既“懂”公司文档,又“守”住数据边界?想象这样一个场景——研发工程师询问年假政策时,系统只返回通…

张小明 2026/1/2 23:28:06 网站建设