Creating a web-browser with Python and PyQT

Python browser PyQt4
Python browser with PyQt4

In this tutorial we will build a webbrowser with Python. We will use the PyQT library which has a web component.  In this tutorial you will learn how to link all the components together. We will use the default rendering engine and not roll one in this tutorial.

If you have not done our pyqt4 beginner tutorial, you could try it. If python-kde4 cannot be found update your repository to find it. The Ubuntu or Debian install guide .

Related course:
Create Simple GUI Applications with Python and Qt

PyQt installation

Install the required packages:

sudo pip install python-qt4
sudo apt-get install qt4-designer
sudo apt-get install pyqt4-dev-tools
sudo apt-get install python-kde4

Creating the GUI with PyQT

Start qt4-designer from your applications menu. The QT Designer application will appear:

QT_Designer
QT_Designer

Select Main Window and press Create. We now have our designer window open.  Drag a KWebView component on the window. If you have a QtWebView in the component list. use that instead. We also add an Line Edit on top. Press File > Save As > browser.ui.  Run the command:

pyuic4 browser.ui > browser.py

This will generate a Python file. Remove the line “from kwebview import KWebView” from the bottom of the browser.py file. Change KWebView to QtWebView. We want to use QtWebView instead. If you are lazy to change that, take the browser.py file from below.

QWebView exploration

Create a file called run.py with this contents:

import sys
from browser import BrowserDialog
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QUrl
from PyQt4.QtWebKit import QWebView
 
class MyBrowser(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        QWebView.__init__(self)
        self.ui = BrowserDialog()
        self.ui.setupUi(self)
        self.ui.lineEdit.returnPressed.connect(self.loadURL)
 
    def loadURL(self):
        url = self.ui.lineEdit.text()
        self.ui.qwebview.load(QUrl(url))
        self.show()  
        #self.ui.lineEdit.setText("")
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = MyBrowser()
    myapp.ui.qwebview.load(QUrl('http://www.pythonspot.com'))
    myapp.show()
    sys.exit(app.exec_())

This code will use the UI as defined in browser.py and add logic to it. The lines

 self.ui.lineEdit.returnPressed.connect(self.loadURL)
 
    def loadURL(self):
        url = self.ui.lineEdit.text()
        self.ui.qwebview.load(QUrl(url))
        self.show()  
        #self.ui.lineEdit.setText("")

The first line defines the callback or event. If a person presses enter (returnPressed), it will call the function loadURL. It makes sure that once you press enter, the page is loaded with that function. If you did everything correctly, you should be able to run the browser with the command:

python run.py

Please make sure you type the full url, e.g.  : http://pythonspot.com including the http:// part.  Your browser should now start:

Python browser
Python browser

If your code does not run, please use the codes below (or look at the differences and change whats wrong):

browser.py

# -*- coding: utf-8 -*-
 
# Form implementation generated from reading ui file 'browser.ui'
#
# Created: Fri Jan 30 20:49:32 2015
#      by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
 
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QUrl
from PyQt4.QtWebKit import QWebView
 
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s
 
try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)
 
class BrowserDialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName(_fromUtf8("Dialog"))
        Dialog.resize(1024, 768)
        self.qwebview = QWebView(Dialog)
        self.qwebview.setGeometry(QtCore.QRect(0, 50, 1020, 711))
        self.qwebview.setObjectName(_fromUtf8("kwebview"))
        self.lineEdit = QtGui.QLineEdit(Dialog)
        self.lineEdit.setGeometry(QtCore.QRect(10, 20, 1000, 25))
        self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
 
        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)
 
    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(_translate("Browser", "Browser", None))

run.py

import sys
from browser import BrowserDialog
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QUrl
from PyQt4.QtWebKit import QWebView
 
class MyBrowser(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        QWebView.__init__(self)
        self.ui = BrowserDialog()
        self.ui.setupUi(self)
        self.ui.lineEdit.returnPressed.connect(self.loadURL)
 
    def loadURL(self):
        url = self.ui.lineEdit.text()
        self.ui.qwebview.load(QUrl(url))
        self.show()  
        #self.ui.lineEdit.setText("")
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = MyBrowser()
    myapp.ui.qwebview.load(QUrl('http://www.pythonspot.com'))
    myapp.show()
    sys.exit(app.exec_())

Download PyQT Code (Bulk Collection)

Create a chrome plugin with Python

chrome extension made with python
Google Chrome extension created with Python (serverless, method B). (click to zoom)
Google Chrome plugins are written in HTML, JavaScript and and CSS. If you have never written a Chrome plugin before I suggest chrome extensions documentation

You can use Python instead of JavaScript and in this tutorial we will show you how to do that.

In a hurry? Download the code from this site:
Download Extension Code
(and scroll down to Method B)

Create an Google Chrome Plugin

To start, we will have to create a manifest file: manifest.json.

{
  "manifest_version": 2,
 
  "name": "Python Chrome Plugin",
  "description": "This extension runs Python code.",
  "version": "1.0",
 
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "permissions": [
    "activeTab",
    "https://ajax.googleapis.com/"
  ]
}

Create a file called popup.html

<!doctype html>
<!--
 This page is shown when the extension button is clicked, because the
 "browser_action" field in manifest.json contains the "default_popup" key with
 value "popup.html".
 -->
<html>
  <head>
    <title>Getting Started Extension's Popup</title>
    <style>
      body {
        font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
        font-size: 100%;
      }
      #status {
        /* avoid an excessively wide status text */
        white-space: pre;
        text-overflow: ellipsis;
        overflow: hidden;
        max-width: 400px;
      }
    </style>
 
    <!--
      - JavaScript and HTML must be in separate files: see our Content Security
      - Policy documentation[1] for details and explanation.
      -
      - [1]: https://developer.chrome.com/extensions/contentSecurityPolicy
     -->
    <script src="popup.js"></script>
  </head>
  <body>
    <div id="status"></div>
    <img id="image-result" hidden>
  </body>
</html>

Finally get an icon and save it as icon.png. Open chrome://extensions and press developer mode. Press “load unpacked extension”, select your directory and press ok.

Adding Python to the Chrome extension

We have two options to add Python into a chrome extension:

  • Method A: Include Brython in an iframe (requires server)
  • Method B: Compile Python to Javascript using Rapydscript (best, serverless, pure extension.)

Method A: Python (Brython) in iframe

Now that you have the basics right we can add Python to the code. To run Python in the browser you have several options including Brython and emcascripten. We decided to give Brython a try. We will run the Brython script from a server. Change popup.html to:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta charset="iso-8859-1">
<style>
body {    
    margin: 0 !important;
    padding: 0 !important;
    width: 800;
}
 
#frame {
    overflow: hidden;
    width:790;
    height:324;
}
</style>
</head>
<body onLoad="">
<iframe src=http://brython.info/console.html id="frame" seamless="seamless" scrolling="no"></iframe>
</body>
</html>

Once you restart your plugin you will have a Python (Brython) interpreter inside your Google Chrome.

Python inside Google Chrome
Python inside Google Chrome

Running your own scripts
To run your own script simply change the url inside the popup.html frame:

<iframe src="BRYTHON SCRIPT URL" id="frame" seamless="seamless" scrolling="no"></iframe>

The script should run on your own server. You can run any Brython script from the web. Using Brython you can simply type Python code inside the script tags. Have a look at this Brython examples or simply browse the gallery.

Method B: Compile Python to Javascript. (no server, pure extension)

There are several tools to compile Python to Javascript. Rapydscript works fine, Pyjs does not work well with chrome (requires special parameter on start).
Install Rapydscript with:

sudo apt-get install npm
sudo ln -s /usr/bin/nodejs /usr/bin/node
sudo npm install rapydscript

Download the code from this site:
Download Extension Code
Change the file /src/hello.py to you needs:

# Example Python script 
# (for rapydscript, a python to javascript compiler)
 
#def doHelloMessage():
#    alert('hello')
#doHelloMessage()
 
# modify html page
document.getElementById("result").innerHTML = 'Compiled Python script in Chrome' 
 
# write into log 
console.log('hello from python')

Run:

./make.sh

You can find your extension in /compiledpythonextension/. Load it in chrome as unpackaged extension and see it working 🙂

Concluding:

Chrome plugins are created using HTML, JavaScript and CSS. We can use Python to create normal Chrome extensions using a Python to Javascript compiler (Rapydscript).

Leave a comment 🙂