Python实现网页截图(PyQT5)过程解析


Posted in Python onAugust 12, 2019

方案说明

功能要求:实现网页加载后将页面截取成长图片

涉及模块:PyQT5 PIL

逻辑说明:

1:完成窗口设置,利用PyQT5 QWebEngineView加载网页地址,待网页加载完成后,调用check_pag;

class MainWindow(QMainWindow):
  def __init__(self, parent=None):
    super(MainWindow, self).__init__(parent)
    self.setWindowTitle('易哈佛')
    self.temp_height = 0
    self.setWindowFlag(Qt.WindowMinMaxButtonsHint, False) # 禁用最大化,最小化
    # self.setWindowFlag(Qt.WindowStaysOnTopHint, True) # 窗口顶置
    self.setWindowFlag(Qt.FramelessWindowHint, True) # 窗口无边框
  def urlScreenShot(self, url):
    self.browser = QWebEngineView()
    self.browser.load(QUrl(url))
    geometry = self.chose_screen()
    self.setGeometry(geometry)
    self.browser.loadFinished.connect(self.check_page)
    self.setCentralWidget(self.browser)
  def get_page_size(self):
    size = self.browser.page().contentsSize()
    self.set_height = size.height()
    self.set_width = size.width()
    return size.width(), size.height()
  def chose_screen(self):
    width, height = 750, 1370
    desktop = QApplication.desktop()
    screen_count = desktop.screenCount()
    for i in range(0, screen_count):
      rect = desktop.availableGeometry(i)
      s_width, s_height = rect.width(), rect.height()
      if s_width > width and s_height > height:
        return QRect(rect.left(), rect.top(), width, height)
    return QRect(0, 0, width, height)
if __name__ == '__main__':
  app = QApplication(sys.argv)
  win = MainWindow()
  win.show()
  app.exit(app.exec_())

2:收集页面高度,并计算分次截屏的次数和余量高度;实例化图片合并工具,设置定时器,超时信号发出后,执行exe_command;

def check_page(self):
    p_width, p_height = self.get_page_size()
    self.page, self.over_flow_size = divmod(p_height, self.height())
    if self.page == 0:
      self.page = 1
    self.ssm = ScreenShotMerge(self.page, self.over_flow_size)
    self.timer = QTimer(self)
    self.timer.timeout.connect(self.exe_command)
    self.timer.setInterval(400)
    self.timer.start()

3:exe_command用来控制截图次数,并在每次截图完成后控制网页向下滑屏幕的高度;所有的页面都已截取时,完成图片合并。

def exe_command(self):
    if self.page > 0:
      self.screen_shot()
      self.run_js()
    elif self.page < 0:
      self.timer.stop()
      self.ssm.image_merge()
      self.close()
    elif self.over_flow_size > 0:
      self.screen_shot()
    self.page -= 1    
  def run_js(self):
    script = """
      var scroll = function (dHeight) {
      var t = document.documentElement.scrollTop
      var h = document.documentElement.scrollHeight
      dHeight = dHeight || 0
      var current = t + dHeight
      if (current > h) {
        window.scrollTo(0, document.documentElement.clientHeight)
       } else {
        window.scrollTo(0, current)
       }
      }
    """
    command = script + '\n scroll({})'.format(self.height())
    self.browser.page().runJavaScript(command)

4:screen_shot在每次截图完成后将图片保存,并将图片对象由图片合并根据保存到列表中。

def screen_shot(self):
    screen = QApplication.primaryScreen()
    winid = self.browser.winId()
    pix = screen.grabWindow(int(winid))
    name = '{}/temp.png'.format(self.ssm.root_path)
    pix.save(name)
    self.ssm.add_im(name)

5:截图合并工具,在每次截图完成后将图片对象保存,完成余量截图的重绘和截图的合并。

class ScreenShotMerge():
  def __init__(self, page, over_flow_size):
    self.im_list = []
    self.page = page
    self.over_flow_size = over_flow_size
    self.get_path()

  def get_path(self):
    self.root_path = Path(__file__).parent.joinpath('temp')
    if not self.root_path.exists():
      self.root_path.mkdir(parents=True)
    self.save_path = self.root_path.joinpath('merge.png')

  def add_im(self, path):
    if len(self.im_list) == self.page:
      im = self.reedit_image(path)
    else:
      im = Image.open(path)
    im.save('{}/{}.png'.format(self.root_path, len(self.im_list) + 1))
    self.im_list.append(im)

  def get_new_size(self):
    max_width = 0
    total_height = 0
    # 计算合成后图片的宽度(以最宽的为准)和高度
    for img in self.im_list:
      width, height = img.size
      if width > max_width:
        max_width = width
      total_height += height
    return max_width, total_height

  def image_merge(self, ):
    if len(self.im_list) > 1:
      max_width, total_height = self.get_new_size()
      # 产生一张空白图
      new_img = Image.new('RGB', (max_width - 15, total_height), 255)
      x = y = 0
      for img in self.im_list:
        width, height = img.size
        new_img.paste(img, (x, y))
        y += height
      new_img.save(self.save_path)
      print('截图成功:', self.save_path)
    else:
      obj = self.im_list[0]
      width, height = obj.size
      left, top, right, bottom = 0, 0, width, height
      box = (left, top, right, bottom)
      region = obj.crop(box)
      new_img = Image.new('RGB', (width, height), 255)
      new_img.paste(region, box)
      new_img.save(self.save_path)
      print('截图成功:', self.save_path)

  def reedit_image(self, path):
    obj = Image.open(path)
    width, height = obj.size
    left, top, right, bottom = 0, height - self.over_flow_size, width, height
    box = (left, top, right, bottom)
    region = obj.crop(box)
    return region

截图功能完整代码

#!/usr/bin/env python
# -*- coding:UTF-8 -*-
# Author:Leslie-x
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
from PIL import Image
from pathlib import Path
class ScreenShotMerge():
  def __init__(self, page, over_flow_size):
    self.im_list = []
    self.page = page
    self.over_flow_size = over_flow_size
    self.get_path()
  def get_path(self):
    self.root_path = Path(__file__).parent.joinpath('temp')
    if not self.root_path.exists():
      self.root_path.mkdir(parents=True)
    self.save_path = self.root_path.joinpath('merge.png')
  def add_im(self, path):
    if len(self.im_list) == self.page:
      im = self.reedit_image(path)
    else:
      im = Image.open(path)
    im.save('{}/{}.png'.format(self.root_path, len(self.im_list) + 1))
    self.im_list.append(im)
  def get_new_size(self):
    max_width = 0
    total_height = 0
    # 计算合成后图片的宽度(以最宽的为准)和高度
    for img in self.im_list:
      width, height = img.size
      if width > max_width:
        max_width = width
      total_height += height
    return max_width, total_height
  def image_merge(self, ):
    if len(self.im_list) > 1:
      max_width, total_height = self.get_new_size()
      # 产生一张空白图
      new_img = Image.new('RGB', (max_width - 15, total_height), 255)
      x = y = 0
      for img in self.im_list:
        width, height = img.size
        new_img.paste(img, (x, y))
        y += height
      new_img.save(self.save_path)
      print('截图成功:', self.save_path)
    else:
      obj = self.im_list[0]
      width, height = obj.size
      left, top, right, bottom = 0, 0, width, height
      box = (left, top, right, bottom)
      region = obj.crop(box)
      new_img = Image.new('RGB', (width, height), 255)
      new_img.paste(region, box)
      new_img.save(self.save_path)
      print('截图成功:', self.save_path)
  def reedit_image(self, path):
    obj = Image.open(path)
    width, height = obj.size
    left, top, right, bottom = 0, height - self.over_flow_size, width, height
    box = (left, top, right, bottom)
    region = obj.crop(box)
    return region
class MainWindow(QMainWindow):
  def __init__(self, parent=None):
    super(MainWindow, self).__init__(parent)
    self.setWindowTitle('易哈佛')
    self.temp_height = 0
    self.setWindowFlag(Qt.WindowMinMaxButtonsHint, False) # 禁用最大化,最小化
    # self.setWindowFlag(Qt.WindowStaysOnTopHint, True) # 窗口顶置
    self.setWindowFlag(Qt.FramelessWindowHint, True) # 窗口无边框
  def urlScreenShot(self, url):
    self.browser = QWebEngineView()
    self.browser.load(QUrl(url))
    geometry = self.chose_screen()
    self.setGeometry(geometry)
    self.browser.loadFinished.connect(self.check_page)
    self.setCentralWidget(self.browser)
  def get_page_size(self):
    size = self.browser.page().contentsSize()
    self.set_height = size.height()
    self.set_width = size.width()
    return size.width(), size.height()
  def chose_screen(self):
    width, height = 750, 1370
    desktop = QApplication.desktop()
    screen_count = desktop.screenCount()
    for i in range(0, screen_count):
      rect = desktop.availableGeometry(i)
      s_width, s_height = rect.width(), rect.height()
      if s_width > width and s_height > height:
        return QRect(rect.left(), rect.top(), width, height)
    return QRect(0, 0, width, height)
  def check_page(self):
    p_width, p_height = self.get_page_size()
    self.page, self.over_flow_size = divmod(p_height, self.height())
    if self.page == 0:
      self.page = 1
    self.ssm = ScreenShotMerge(self.page, self.over_flow_size)
    self.timer = QTimer(self)
    self.timer.timeout.connect(self.exe_command)
    self.timer.setInterval(400)
    self.timer.start()
  def exe_command(self):
    if self.page > 0:
      self.screen_shot()
      self.run_js()

    elif self.page < 0:
      self.timer.stop()
      self.ssm.image_merge()
      self.close()

    elif self.over_flow_size > 0:
      self.screen_shot()
    self.page -= 1

  def run_js(self):
    script = """
      var scroll = function (dHeight) {
      var t = document.documentElement.scrollTop
      var h = document.documentElement.scrollHeight
      dHeight = dHeight || 0
      var current = t + dHeight
      if (current > h) {
        window.scrollTo(0, document.documentElement.clientHeight)
       } else {
        window.scrollTo(0, current)
       }
      }
    """
    command = script + '\n scroll({})'.format(self.height())
    self.browser.page().runJavaScript(command)

  def screen_shot(self):
    screen = QApplication.primaryScreen()
    winid = self.browser.winId()
    pix = screen.grabWindow(int(winid))
    name = '{}/temp.png'.format(self.ssm.root_path)
    pix.save(name)
    self.ssm.add_im(name)

if __name__ == '__main__':
  url = 'http://blog.sina.com.cn/lm/rank/focusbang//'
  app = QApplication(sys.argv)
  win = MainWindow()
  win.urlScreenShot(url)
  win.show()
  app.exit(app.exec_())

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python多线程编程(五):死锁的形成
Apr 05 Python
Python 多线程实例详解
Mar 25 Python
Python 网页解析HTMLParse的实例详解
Aug 10 Python
PyQt5主窗口动态加载Widget实例代码
Feb 07 Python
Python使用Selenium爬取淘宝异步加载的数据方法
Dec 17 Python
详解Python静态网页爬取获取高清壁纸
Apr 23 Python
使用python分析统计自己微信朋友的信息
Jul 19 Python
简单了解Django应用app及分布式路由
Jul 24 Python
python3的url编码和解码,自定义gbk、utf-8的例子
Aug 22 Python
python变量的作用域是什么
May 26 Python
Selenium Webdriver元素定位的八种常用方式(小结)
Jan 13 Python
django使用多个数据库的方法实例
Mar 04 Python
python实现知乎高颜值图片爬取
Aug 12 #Python
python3 enum模块的应用实例详解
Aug 12 #Python
Python一键查找iOS项目中未使用的图片、音频、视频资源
Aug 12 #Python
django+echart数据动态显示的例子
Aug 12 #Python
Flask框架学习笔记之使用Flask实现表单开发详解
Aug 12 #Python
Flask框架学习笔记之表单基础介绍与表单提交方式
Aug 12 #Python
python内存管理机制原理详解
Aug 12 #Python
You might like
FirePHP 推荐一款PHP调试工具
2011/04/23 PHP
jQuery 源码分析笔记
2011/05/25 PHP
thinkphp5框架路由原理与用法详解
2020/02/11 PHP
javascript中获取下个月一号,是星期几
2012/06/01 Javascript
深入理解javascript学习笔记(一) 编写高质量代码
2012/08/09 Javascript
关于在IE下的一个安全BUG --可用于跟踪用户的系统鼠标位置
2013/04/17 Javascript
JS写的贪吃蛇游戏(个人练习)
2013/07/08 Javascript
json传值以及ajax接收详解
2016/05/24 Javascript
Three.js学习之网格
2016/08/10 Javascript
jQuery实现可展开折叠的导航效果示例
2016/09/12 Javascript
让html元素随浏览器的大小自适应垂直居中的实现方法
2016/10/12 Javascript
js实现一个简单的数字时钟效果
2017/03/29 Javascript
vue2手机APP项目添加开屏广告或者闪屏广告
2017/11/28 Javascript
详解js获取video任意时间的画面截图
2019/04/17 Javascript
基于javascript的拖拽类封装详解
2019/04/19 Javascript
vue 在单页面应用里使用二级套嵌路由
2020/12/19 Vue.js
[54:26]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第一场 12.10
2020/12/12 DOTA
python实现的一个火车票转让信息采集器
2014/07/09 Python
Python标准库之sqlite3使用实例
2014/11/25 Python
Python三级目录展示的实现方法
2016/09/28 Python
新手如何快速入门Python(菜鸟必看篇)
2017/06/10 Python
Python numpy 常用函数总结
2017/12/07 Python
2018年Python值得关注的开源库、工具和开发者(总结篇)
2018/01/04 Python
Python爬虫beautifulsoup4常用的解析方法总结
2019/02/25 Python
linux中如何使用python3获取ip地址
2019/07/15 Python
导出HTML5 Canvas图片并上传服务器功能
2019/08/16 HTML / CSS
英国领先的酒杯和水晶玻璃器皿制造商:Dartington Crystal
2019/06/23 全球购物
奥巴马演讲稿
2014/01/08 职场文书
《翻越远方的大山》教学反思
2014/04/13 职场文书
小学数学教学经验交流材料
2014/05/22 职场文书
抗震救灾标语
2014/06/26 职场文书
关于青春的演讲稿三分钟
2014/08/22 职场文书
工作失误检讨书(经典集锦版)
2014/10/17 职场文书
优秀英文求职信范文
2015/03/19 职场文书
2016年毕业实习心得体会范文
2015/10/09 职场文书
Python序列化模块JSON与Pickle
2022/06/05 Python