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代码
Mar 13 Python
python多线程编程方式分析示例详解
Dec 06 Python
Python3基础之基本数据类型概述
Aug 13 Python
Python中转换角度为弧度的radians()方法
May 18 Python
快速排序的算法思想及Python版快速排序的实现示例
Jul 02 Python
python生成式的send()方法(详解)
May 08 Python
python按行读取文件,去掉每行的换行符\n的实例
Apr 19 Python
Python实现判断一行代码是否为注释的方法
May 23 Python
int在python中的含义以及用法
Jun 27 Python
pytorch使用tensorboardX进行loss可视化实例
Feb 24 Python
python多进程下的生产者和消费者模型
May 07 Python
学会用Python实现滑雪小游戏,再也不用去北海道啦
May 20 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
Terran热键控制
2020/03/14 星际争霸
如何从一个php文件向另一个地址post数据,不用表单和隐藏的变量的
2007/03/06 PHP
用Simple Excel导出xls实现方法
2012/12/06 PHP
解读PHP中的垃圾回收机制
2015/08/10 PHP
Laravel中9个不经常用的小技巧汇总
2019/04/16 PHP
使用 JScript 创建 .exe 或 .dll 文件的方法
2011/07/13 Javascript
Extjs优化(二)Form表单提交通用实现
2013/04/15 Javascript
Jquery增加鼠标中间功能mousewheel的实例代码
2013/09/05 Javascript
jquery实现两个图片渐变切换效果的方法
2015/06/25 Javascript
jQuery实现美观的多级动画效果菜单代码
2015/09/06 Javascript
JavaScript仿商城实现图片广告轮播实例代码
2016/02/06 Javascript
js获取html的span标签的值方法(超简单)
2016/07/26 Javascript
js实现添加可信站点、修改activex安全设置,禁用弹出窗口阻止程序
2016/08/17 Javascript
谈谈第三方App接入微信登录 解读
2016/12/27 Javascript
js按条件生成随机json:randomjson实现方法
2017/04/07 Javascript
vue路由跳转时判断用户是否登录功能的实现
2017/10/26 Javascript
Vue.js+Layer表格数据绑定与实现更新的实例
2018/03/07 Javascript
Vue中JS动画与Velocity.js的结合使用
2019/02/13 Javascript
使用Vue父子组件通信实现todolist的功能示例代码
2019/04/11 Javascript
微信小程序中weui用法解析
2019/10/21 Javascript
利用React高阶组件实现一个面包屑导航的示例
2020/08/23 Javascript
python ElementTree 基本读操作示例
2009/04/09 Python
python正则表达式re模块详解
2014/06/25 Python
Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息示例
2018/07/18 Python
Python subprocess库的使用详解
2018/10/26 Python
澳大利亚免息网上购物:Shop Zero
2016/09/17 全球购物
Dogeared官网:在美国手工制作的珠宝
2019/08/24 全球购物
一些.net面试题
2014/10/06 面试题
优纳科技软件测试面试题
2012/05/15 面试题
会计助理的岗位职责
2013/11/29 职场文书
汽车队司机先进事迹材料
2014/02/01 职场文书
绘画专业自荐信范文
2014/02/23 职场文书
环保建议书
2014/03/12 职场文书
幼教求职信
2014/03/12 职场文书
销售职业生涯规划范文
2014/03/14 职场文书
优秀食品类广告词
2014/03/19 职场文书