2

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.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
vesuvius
  • 435
  • 4
  • 20

1 Answers1

2

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_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks for this, although I am able to see clickable links but when I click on them, the respective link doesn't open and the whole textbrowser goes blank and I receive this `QTextBrowser: No document for https://somelink.com/ PyQt5.QtCore.QUrl('https://somelink.com/')` – vesuvius Feb 25 '20 at 05:43
  • @vesuvius What do you want to happen when the link is clicked? In your question you just want the links to be clickable which my code does, then I don't know what you want to happen when a link is clicked. – eyllanesc Feb 25 '20 at 05:48
  • sorry for that, I want when the link is clicked, it opens it in a web browser and when it is clicked the textbrowser doesn't go blank but should still retain all the links. – vesuvius Feb 25 '20 at 05:51
  • @vesuvius 1) Do you want this URL to open the webdriver search engine or the default search engine of your OS? 2) You should edit your question and add what you want to happen when clicked – eyllanesc Feb 25 '20 at 05:54
  • I've added an `Edit` part at the bottom of the question, could you please check :) – vesuvius Feb 25 '20 at 05:59