pythonpyqtpyqt5qtextbrowser

How to display a clickable hyperlink in QTextBrowser


I've created a GUI in which you enter something, in the search bar, it goes directly into duckduckgo and searches for the entered element and then it prints all the hyperlinks in a QTextBrowser. But the links are not clickable. I don't know how to make it clickable.I'd really appreciate if you guys could help me. The main function isinput_value where I've written the back-end process. This is my code:

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import QAbstractTableModel, Qt
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import pyautogui


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(875, 648)
        MainWindow.setAutoFillBackground(False)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.searchforpoi = QtWidgets.QPushButton(self.centralwidget)
        self.searchforpoi.setGeometry(QtCore.QRect(730, 20, 111, 34))
        self.searchforpoi.setObjectName("searchforpoi")
        self.searchforpoi.clicked.connect(self.input_value)
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(20, 20, 691, 31))
        self.lineEdit.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
        self.lineEdit.setObjectName("lineEdit")
        self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
        self.textBrowser.setGeometry(QtCore.QRect(25, 71, 821, 551))
        self.textBrowser.setObjectName("textBrowser")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "POI Updation app"))
        self.searchforpoi.setText(_translate("MainWindow", "Search for POI"))

    def input_value(self):
        options = webdriver.ChromeOptions()
        options.headless = True
        textboxValue = self.lineEdit.text()
        browser = webdriver.Chrome()
        browser.implicitly_wait(30)
        browser.maximize_window()

        browser.get("http://www.duckduckgo.com")
        elem = browser.find_element_by_name("q")
        elem.clear()

        elem.send_keys(textboxValue)
        elem.submit()

        lists = browser.find_elements_by_class_name("result__url__domain")

        for a in browser.find_elements_by_xpath('.//a'):
            ab = a.get_attribute('href')
            self.textBrowser.append(ab)

        browser.quit()


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Edit:- When the link is clicked, it should open a default web browser and the QTextBrowser should retain all the other links.


Solution

  • The tasks that consume a lot of time must be executed in a secondary thread and send the information through signals, on the other hand, passing the urls as text does not make them clickable, what you should do is use "href". In order not to change the page, the QTextBrowser (links not removed) must open the property OpenLinks to False. To open the url in OS default browser then you must use QDesktopServices.openUrl():

    import threading
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(875, 648)
            MainWindow.setAutoFillBackground(False)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            self.searchforpoi = QtWidgets.QPushButton(self.centralwidget)
            self.searchforpoi.setGeometry(QtCore.QRect(730, 20, 111, 34))
            self.searchforpoi.setObjectName("searchforpoi")
    
            self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
            self.lineEdit.setGeometry(QtCore.QRect(20, 20, 691, 31))
            self.lineEdit.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
            self.lineEdit.setObjectName("lineEdit")
            self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
            self.textBrowser.setGeometry(QtCore.QRect(25, 71, 821, 551))
            self.textBrowser.setObjectName("textBrowser")
            MainWindow.setCentralWidget(self.centralwidget)
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
    
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "POI Updation app"))
            self.searchforpoi.setText(_translate("MainWindow", "Search for POI"))
    
    
    class DriverWorker(QtCore.QObject):
        urlsSignals = QtCore.pyqtSignal(list)
    
        def get_urls(self, text):
            threading.Thread(target=self._task, args=(text,), daemon=True).start()
    
        def _task(self, text):
            options = webdriver.ChromeOptions()
            options.headless = True
            browser = webdriver.Chrome()
            browser.implicitly_wait(30)
            browser.maximize_window()
    
            browser.get("http://www.duckduckgo.com")
            elem = browser.find_element_by_name("q")
            elem.clear()
    
            elem.send_keys(text)
            elem.submit()
    
            lists = browser.find_elements_by_class_name("result__url__domain")
    
            urls = []
            for a in browser.find_elements_by_xpath(".//a"):
                ab = a.get_attribute("href")
                urls.append(ab)
            self.urlsSignals.emit(urls)
            browser.quit()
    
    
    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setupUi(self)
            self.searchforpoi.clicked.connect(self.input_value)
            self.worker = DriverWorker()
            self.worker.urlsSignals.connect(self.on_urls)
            self.textBrowser.anchorClicked.connect(QtGui.QDesktopServices.openUrl)
            self.textBrowser.setOpenLinks(False)
    
        @QtCore.pyqtSlot()
        def input_value(self):
            textboxValue = self.lineEdit.text()
            self.worker.get_urls(textboxValue)
    
        @QtCore.pyqtSlot(list)
        def on_urls(self, urls):
            self.textBrowser.clear()
            for url in urls:
                html = """<a href="{url}">{url}</a>""".format(url=url)
                self.textBrowser.append(html)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())