PyQt5内嵌浏览器注入JavaScript脚本实现自动化操作的代码实例


Posted in Python onFebruary 13, 2019

概要

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

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

  1. 使用 QWebEngineView 加载网页,并显示进度。
  2. 在默认配置(QWebEngineProfile)中植入 Javascript 内容,这样脚本会在所有打开的网页中执行,不论跳转到哪个网址。
  3. Javascript 脚本使用网址中的路径名,判断当前网页位置,从而决定执行哪种操作。

python 代码示例

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''使用 PyQt5 内嵌浏览器浏览网页,并注入 Javascript 脚本实现自动化操作。'''
import os
import sys
from datetime import datetime
from PyQt5.QtWidgets import (
  QWidget, QApplication, QVBoxLayout, QHBoxLayout,
  QDesktopWidget, QTextEdit, QLabel, QLineEdit, QPushButton,
  QFileDialog, QProgressBar,
)
from PyQt5.QtCore import QUrl, pyqtSlot
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile, QWebEngineScript, QWebEnginePage
class Browser(QWidget):
  def __init__(self):
    super().__init__()
    self.init_ui()
    # 脚本
    self.profile = QWebEngineProfile.defaultProfile()
    self.script = QWebEngineScript()
    self.prepare_script()
  def init_ui(self):
    self.webView = QWebEngineView()
    self.logEdit = QTextEdit()
    self.logEdit.setFixedHeight(100)
    self.addrEdit = QLineEdit()
    self.addrEdit.returnPressed.connect(self.load_url)
    self.webView.urlChanged.connect(
      lambda i: self.addrEdit.setText(i.toDisplayString()))
    self.jsEdit = QLineEdit()
    self.jsEdit.setText('inject.js')
    loadUrlBtn = QPushButton('加载')
    loadUrlBtn.clicked.connect(self.load_url)
    chooseJsBtn = QPushButton('选择脚本文件')
    chooseJsBtn.clicked.connect(self.choose_js_file)
    # 导航/工具
    top = QWidget()
    top.setFixedHeight(80)
    topBox = QVBoxLayout(top)
    topBox.setSpacing(0)
    topBox.setContentsMargins(5, 0, 0, 5)
    progBar = QProgressBar()
    progBox = QHBoxLayout()
    progBox.addWidget(progBar)
    topBox.addLayout(progBox)
    naviBox = QHBoxLayout()
    naviBox.addWidget(QLabel('网址'))
    naviBox.addWidget(self.addrEdit)
    naviBox.addWidget(loadUrlBtn)
    topBox.addLayout(naviBox)
    naviBox = QHBoxLayout()
    naviBox.addWidget(QLabel('注入脚本文件'))
    naviBox.addWidget(self.jsEdit)
    naviBox.addWidget(chooseJsBtn)
    topBox.addLayout(naviBox)
    self.webView.loadProgress.connect(progBar.setValue)
    # 主界面
    layout = QVBoxLayout(self)
    layout.addWidget(self.webView)
    layout.addWidget(top)
    layout.addWidget(self.logEdit)
    self.show()
    self.resize(1024, 900)
    self.center()
  def center(self):
    qr = self.frameGeometry()
    cp = QDesktopWidget().availableGeometry().center()
    qr.moveCenter(cp)
    self.move(qr.topLeft())
  @pyqtSlot()
  def load_url(self):
    url = self.addrEdit.text().strip()
    if not url.lower().startswith('http://') \
        and not url.lower().startswith('https://'):
      url = 'http://{}'.format(url)
    self.load(url)
  @pyqtSlot()
  def choose_js_file(self):
    f, _ = QFileDialog.getOpenFileName(filter="Javascript files(*.js)")
    if os.path.isfile(f):
      self.jsEdit.setText(f)
      self.prepare_script()
  def prepare_script(self):
    path = self.jsEdit.text().strip()
    if not os.path.isfile(path):
      self.log('invalid js path')
      return
    self.profile.scripts().remove(self.script)
    with open(path, 'r') as f:
      self.script.setSourceCode(f.read())
    self.profile.scripts().insert(self.script)
    self.log('injected js ready')
  def log(self, msg, *args, **kwargs):
    m = msg.format(*args, **kwargs)
    self.logEdit.append('{} {}'.format(
      datetime.now().strftime('%H:%M:%S'), m))
  def load(self, url):
    self.log(f'loading {url}')
    self.addrEdit.setText(url)
    self.webView.load(QUrl(url))
if __name__ == '__main__':
  app = QApplication(sys.argv)
  b = Browser()
  b.load('http://www.flyscoot.com/')
  sys.exit(app.exec_())

Javascript 脚本示例

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

Python 相关文章推荐
python基于xml parse实现解析cdatasection数据
Sep 30 Python
Python实现抓取页面上链接的简单爬虫分享
Jan 21 Python
python中的__slots__使用示例
Feb 26 Python
简单的python后台管理程序
Apr 13 Python
Windows环境下python环境安装使用图文教程
Mar 13 Python
python opencv捕获摄像头并显示内容的实现
Jul 11 Python
pandas的排序和排名的具体使用
Jul 31 Python
python Qt5实现窗体跟踪鼠标移动
Dec 13 Python
用python对excel进行操作(读,写,修改)
Dec 25 Python
python如何进行基准测试
Apr 26 Python
Python实现PIL图像处理库绘制国际象棋棋盘
Jul 16 Python
python神经网络Xception模型
May 06 Python
Python实现Event回调机制的方法
Feb 13 #Python
Python socket实现多对多全双工通信的方法
Feb 13 #Python
对python文件读写的缓冲行为详解
Feb 13 #Python
python单线程文件传输的实例(C/S)
Feb 13 #Python
Python 实现文件打包、上传与校验的方法
Feb 13 #Python
使用python3构建文件传输的方法
Feb 13 #Python
对python 自定义协议的方法详解
Feb 13 #Python
You might like
常用星际术语索引(新手指南)
2020/03/04 星际争霸
js修改地址栏URL参数解决url参数问题
2012/12/15 Javascript
JS获取文本框,下拉框,单选框的值的简单实例
2014/02/26 Javascript
js特殊字符过滤的示例代码
2014/03/05 Javascript
AngularJS入门教程之 XMLHttpRequest实例讲解
2016/07/27 Javascript
关于jquery中动态增加select,事件无效的快速解决方法
2016/08/29 Javascript
深入理解javascript中concat方法
2016/12/12 Javascript
js数字滑动时钟的简单实现(示例讲解)
2017/08/14 Javascript
详谈js对url进行编码和解码(三种方式的区别)
2017/08/16 Javascript
微信小程序的日期选择器的实例详解
2017/09/29 Javascript
vue实现前进刷新后退不刷新效果
2018/01/26 Javascript
React中使用UEditor百度富文本的方法
2018/08/22 Javascript
trackingjs+websocket+百度人脸识别API实现人脸签到
2018/11/26 Javascript
JS中的算法与数据结构之字典(Dictionary)实例详解
2019/08/20 Javascript
vue+canvas实现移动端手写签名
2020/05/21 Javascript
JS相册图片抖动放大展示效果的示例代码
2021/01/29 Javascript
python模拟新浪微博登陆功能(新浪微博爬虫)
2013/12/24 Python
python实现爬虫下载美女图片
2015/07/14 Python
手把手教你如何安装Pycharm(详细图文教程)
2018/11/28 Python
浅析Python 实现一个自动化翻译和替换的工具
2019/04/14 Python
python pygame实现挡板弹球游戏
2019/11/25 Python
np.dot()函数的用法详解
2020/01/17 Python
Python socket处理client连接过程解析
2020/03/18 Python
TensorFlow实现模型断点训练,checkpoint模型载入方式
2020/05/26 Python
HTML5计时器小例子
2013/10/15 HTML / CSS
Html5新增标签有哪些
2017/04/13 HTML / CSS
Html5调用手机摄像头并实现人脸识别的实现
2018/12/21 HTML / CSS
英国最大的手表网站:The Watch Hut
2017/03/31 全球购物
印度尼西亚最大和最全面的网络商城:Blibli.com
2017/10/04 全球购物
Etam德国:内衣精品店
2019/08/25 全球购物
PHP开发的一般流程
2013/08/13 面试题
什么是用户模式(User Mode)与内核模式(Kernel Mode) ?
2014/07/21 面试题
国家助学金感谢信
2015/01/21 职场文书
大学生年度个人总结
2015/02/15 职场文书
员工辞退通知书
2015/04/17 职场文书
2015入党个人自传范文
2015/06/26 职场文书