资讯专栏INFORMATION COLUMN

PyQt5 内嵌浏览器注入 Javascript 脚本实现自动化操作

xiguadada / 2205人阅读

摘要:概要应同学邀请,演示如何使用内嵌浏览器浏览网页,并注入脚本实现自动化操作。在默认配置中植入内容,这样脚本会在所有打开的网页中执行,不论跳转到哪个网址。脚本使用网址中的路径名,判断当前网页位置,从而决定执行哪种操作。

概要

应同学邀请,演示如何使用 PyQt5 内嵌浏览器浏览网页,并注入 Javascript 脚本实现自动化操作。

sg 原贴地址: 如何在Python利用runJavaScript模拟鼠标移动页面的某个元素
https://segmentfault.com/q/10...

下面测试的是一个廉价机票预订网站(http://www.flyscoot.com/),关键点如下

使用 QWebEngineView 加载网页,并显示进度。

在默认配置(QWebEngineProfile)中植入 Javascript 内容,这样脚本会在所有打开的网页中执行,不论跳转到哪个网址。

Javascript 脚本使用网址中的路径名,判断当前网页位置,从而决定执行哪种操作。

python 代码示例

</>复制代码

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """使用 PyQt5 内嵌浏览器浏览网页,并注入 Javascript 脚本实现自动化操作。"""
  4. import os
  5. import sys
  6. from datetime import datetime
  7. from PyQt5.QtWidgets import (
  8. QWidget, QApplication, QVBoxLayout, QHBoxLayout,
  9. QDesktopWidget, QTextEdit, QLabel, QLineEdit, QPushButton,
  10. QFileDialog, QProgressBar,
  11. )
  12. from PyQt5.QtCore import QUrl, pyqtSlot
  13. from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile, QWebEngineScript, QWebEnginePage
  14. class Browser(QWidget):
  15. def __init__(self):
  16. super().__init__()
  17. self.init_ui()
  18. # 脚本
  19. self.profile = QWebEngineProfile.defaultProfile()
  20. self.script = QWebEngineScript()
  21. self.prepare_script()
  22. def init_ui(self):
  23. self.webView = QWebEngineView()
  24. self.logEdit = QTextEdit()
  25. self.logEdit.setFixedHeight(100)
  26. self.addrEdit = QLineEdit()
  27. self.addrEdit.returnPressed.connect(self.load_url)
  28. self.webView.urlChanged.connect(
  29. lambda i: self.addrEdit.setText(i.toDisplayString()))
  30. self.jsEdit = QLineEdit()
  31. self.jsEdit.setText("inject.js")
  32. loadUrlBtn = QPushButton("加载")
  33. loadUrlBtn.clicked.connect(self.load_url)
  34. chooseJsBtn = QPushButton("选择脚本文件")
  35. chooseJsBtn.clicked.connect(self.choose_js_file)
  36. # 导航/工具
  37. top = QWidget()
  38. top.setFixedHeight(80)
  39. topBox = QVBoxLayout(top)
  40. topBox.setSpacing(0)
  41. topBox.setContentsMargins(5, 0, 0, 5)
  42. progBar = QProgressBar()
  43. progBox = QHBoxLayout()
  44. progBox.addWidget(progBar)
  45. topBox.addLayout(progBox)
  46. naviBox = QHBoxLayout()
  47. naviBox.addWidget(QLabel("网址"))
  48. naviBox.addWidget(self.addrEdit)
  49. naviBox.addWidget(loadUrlBtn)
  50. topBox.addLayout(naviBox)
  51. naviBox = QHBoxLayout()
  52. naviBox.addWidget(QLabel("注入脚本文件"))
  53. naviBox.addWidget(self.jsEdit)
  54. naviBox.addWidget(chooseJsBtn)
  55. topBox.addLayout(naviBox)
  56. self.webView.loadProgress.connect(progBar.setValue)
  57. # 主界面
  58. layout = QVBoxLayout(self)
  59. layout.addWidget(self.webView)
  60. layout.addWidget(top)
  61. layout.addWidget(self.logEdit)
  62. self.show()
  63. self.resize(1024, 900)
  64. self.center()
  65. def center(self):
  66. qr = self.frameGeometry()
  67. cp = QDesktopWidget().availableGeometry().center()
  68. qr.moveCenter(cp)
  69. self.move(qr.topLeft())
  70. @pyqtSlot()
  71. def load_url(self):
  72. url = self.addrEdit.text().strip()
  73. if not url.lower().startswith("http://")
  74. and not url.lower().startswith("https://"):
  75. url = "http://{}".format(url)
  76. self.load(url)
  77. @pyqtSlot()
  78. def choose_js_file(self):
  79. f, _ = QFileDialog.getOpenFileName(filter="Javascript files(*.js)")
  80. if os.path.isfile(f):
  81. self.jsEdit.setText(f)
  82. self.prepare_script()
  83. def prepare_script(self):
  84. path = self.jsEdit.text().strip()
  85. if not os.path.isfile(path):
  86. self.log("invalid js path")
  87. return
  88. self.profile.scripts().remove(self.script)
  89. with open(path, "r") as f:
  90. self.script.setSourceCode(f.read())
  91. self.profile.scripts().insert(self.script)
  92. self.log("injected js ready")
  93. def log(self, msg, *args, **kwargs):
  94. m = msg.format(*args, **kwargs)
  95. self.logEdit.append("{} {}".format(
  96. datetime.now().strftime("%H:%M:%S"), m))
  97. def load(self, url):
  98. self.log(f"loading {url}")
  99. self.addrEdit.setText(url)
  100. self.webView.load(QUrl(url))
  101. if __name__ == "__main__":
  102. app = QApplication(sys.argv)
  103. b = Browser()
  104. b.load("http://www.flyscoot.com/")
  105. sys.exit(app.exec_())
Javascript 脚本示例

</>复制代码

  1. // 简单起见,这里只演示部分页面,脚本内容摘自 Heng丶原贴文。
  2. function handle(path) {
  3. // 首页
  4. if (path == "/zh") {
  5. document.getElementsByClassName("radio-inline")[1].click();
  6. document.getElementById("oneway_from").value="广州 (CAN)";
  7. document.getElementById("oneway_to").value="新加坡 (SIN)";
  8. document.getElementById("oneway_departuredate").value="2018年9月10日";
  9. document.getElementsByClassName("btn--booking")[1].click();
  10. return;
  11. }
  12. // 选择航班
  13. if (path == "/Book/Flight") {
  14. document.getElementsByClassName("price--sale")[0].click();
  15. document.getElementsByClassName("heading-4")[0].click();
  16. document.getElementsByClassName("btn-submit")[0].click();
  17. return;
  18. }
  19. // 乘客信息
  20. if (path == "/BookFlight/Passengers") {
  21. document.getElementsByClassName("fname1")[0].value = "匿名";
  22. }
  23. }
  24. let host = document.location.hostname;
  25. if (host.endsWith(".flyscoot.com")) {
  26. handle(document.location.pathname);
  27. }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/42341.html

相关文章

  • chrome扩展开发之旅 第二篇

    摘要:跨域请求跨域问题,是开发中一直以来需要注意的问题。则发送通道的发送给监听此消息的外部扩展。完整方法此处,为必选参数,为回调函数。回调函数接收到的参数有三个,分别是和,即消息内容,消息发送者相关信息和相应函数。是发起消息的标签。 第二章简介 第二章较第一章复杂许多。书中虽寥寥21页,内容却也不少。涵盖了8个小节。 2.1 操作用户正在浏览的页面 2.2 跨域请求 2.3 常驻后台 2....

    shadajin 评论0 收藏0
  • webpack实战

    摘要:和类似的预处理器还有等。的用处非常多,包括给自动加前缀使用下一代语法等,目前越来越多的人开始用它,它很可能会成为预处理器的最终赢家。 webpack实战 查看所有文档页面:全栈开发,获取更多信息。快马加鞭,加班加点,终于把这个文档整理出来了,顺便深入地学习一番,巩固知识,就是太累人,影响睡眠时间和质量。极客就是想要把事情做到极致,开始了就必须到达终点。 原文链接:webpack实战,原...

    cyrils 评论0 收藏0
  • JavaScript性能优化之加载与执行

    摘要:在浏览区中的性能,可以认为是开发者所面临的最严重的可用性问题。优化这个问题的第一步从它的加载和执行开始。这意味着在对象的事件触发后再下载脚本。属性指明本元素所含的脚本不会修改,因此代码能够安全地执行,但是浏览器的支持情况不理想。 JavaScript在浏览区中的性能,可以认为是开发者所面临的最严重的可用性问题。 优化这个问题的第一步从它的加载和执行开始。 霸道的script标签scr...

    call_me_R 评论0 收藏0
  • 延迟脚本的方式

    摘要:实现延迟加载的方式有方式一标签放在底部将节点放置在之前,这样脚本会在页面显示出来之后再加载。尽可能地合并脚本。采用无阻塞下载脚本的方法使用标签的属性仅适用于和以上版本使用动态创建的元素来下载并执行代码使用对象下载代码并注入页面中。 昨晚‘今日头条’笔试题中遇到这道题,今天专门查了一下。 从 IE 8、Firefox 3.5、Safari 4 和 Chrome 2 开始都允许并行下载 J...

    tinylcy 评论0 收藏0
  • web security

    摘要:是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。 常见web安全及防护原理 sql注入原理 就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令 总的来说有以下几点 永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双-进行转换等 永远不要使用动态拼装SQL,可以...

    livem 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<