Asked  6 Months ago    Answers:  5   Viewed   29 times

I want to use PhantomJS in Python. I googled this problem but couldn't find proper solutions.

I find os.popen() may be a good choice. But I couldn't pass some arguments to it.

Using subprocess.Popen() may be a proper solution for now. I want to know whether there's a better solution or not.

Is there a way to use PhantomJS in Python?

 Answers

79

The easiest way to use PhantomJS in python is via Selenium. The simplest installation method is

  1. Install NodeJS
  2. Using Node's package manager install phantomjs: npm -g install phantomjs-prebuilt
  3. install selenium (in your virtualenv, if you are using that)

After installation, you may use phantom as simple as:

from selenium import webdriver

driver = webdriver.PhantomJS() # or add to your PATH
driver.set_window_size(1024, 768) # optional
driver.get('https://google.com/')
driver.save_screenshot('screen.png') # save a screenshot to disk
sbtn = driver.find_element_by_css_selector('button.gbqfba')
sbtn.click()

If your system path environment variable isn't set correctly, you'll need to specify the exact path as an argument to webdriver.PhantomJS(). Replace this:

driver = webdriver.PhantomJS() # or add to your PATH

... with the following:

driver = webdriver.PhantomJS(executable_path='/usr/local/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs')

References:

  • http://selenium-python.readthedocs.io/
  • How do I set a proxy for phantomjs/ghostdriver in python webdriver?
  • https://dzone.com/articles/python-testing-phantomjs
Tuesday, June 1, 2021
 
pamelus
answered 6 Months ago
19

I solved same promlem with this command in command line

export PATH=${PATH:+$PATH:}/home/<login>/phantomjs/bin

It's work if /home/login/phantomjs/bin is the path for folder with executable 'phantomjs'.

Thursday, June 24, 2021
 
JustSteveKing
answered 6 Months ago
89

Two key things that helped me to solve it:

  • do not use that custom wait I've helped you with before
  • set the window.document.body.scrollTop first to 0 and then to document.body.scrollHeight in a row

Working code:

results = []
while len(results) < 200:
    results = driver.find_elements_by_css_selector("div.flightbox")

    print len(results)

    # scroll
    driver.execute_script("arguments[0].scrollIntoView();", results[0])
    driver.execute_script("window.document.body.scrollTop = 0;")
    driver.execute_script("window.document.body.scrollTop = document.body.scrollHeight;")
    driver.execute_script("arguments[0].scrollIntoView();", results[-1])

Version 2 (endless loop, stop if there is nothing loaded on scroll anymore):

results = []
while True:
    try:
        wait.until(wait_for_more_than_n_elements((By.CSS_SELECTOR, "div.flightbox"), len(results)))
    except TimeoutException:
        break

    results = self.driver.find_elements_by_css_selector("div.flightbox")
    print len(results)

    # scroll
    for _ in xrange(5):
        try:
            self.driver.execute_script("""
                arguments[0].scrollIntoView();
                window.document.body.scrollTop = 0;
                window.document.body.scrollTop = document.body.scrollHeight;
                arguments[1].scrollIntoView();
            """, results[0], results[-1])
        except StaleElementReferenceException:
            break  # here it means more results were loaded

print "DONE. Result count: %d" % len(results)

Note that I've changed the comparison in the wait_for_more_than_n_elements expected condition. Replaced:

return count >= self.count

with:

return count > self.count

Version 3 (scrolling from header to footer multiple times):

header = wait.until(EC.visibility_of_element_located((By.TAG_NAME, 'header')))
footer = wait.until(EC.visibility_of_element_located((By.TAG_NAME, 'footer')))

results = []
while True:
    try:
        wait.until(wait_for_more_than_n_elements((By.CSS_SELECTOR, "div.flightbox"), len(results)))
    except TimeoutException:
        break

    results = self.driver.find_elements_by_css_selector("div.flightbox")
    print len(results)

    # scroll
    for _ in xrange(5):
        self.driver.execute_script("""
            arguments[0].scrollIntoView();
            arguments[1].scrollIntoView();
        """, header, footer)
        sleep(1)
Sunday, August 15, 2021
 
Kyle Vassella
answered 4 Months ago
59

uic.loadUi

If you use the loadUi method it doesn't implement the retranslateUi method so if you use that method then the solution is the same as the previous post.

demo.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Demo</class>
 <widget class="QWidget" name="Demo">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>102</width>
    <height>108</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QComboBox" name="combo"/>
   </item>
   <item>
    <widget class="QPushButton" name="button">
     <property name="text">
      <string>Start</string>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QLabel" name="label">
     <property name="text">
      <string>Hello, World</string>
     </property>
     <property name="alignment">
      <set>Qt::AlignCenter</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

main.py

import sys
from PyQt5 import QtCore, QtGui, QtWidgets, uic


class Demo(QtWidgets.QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        uic.loadUi("demo.ui", self)

        self.combo.currentIndexChanged.connect(self.change_func)

        self.trans = QtCore.QTranslator(self)

        options = [
            ("English", ""),
            ("français", "eng-fr"),
            ("中文", "eng-chs"),
        ]

        for i, (text, lang) in enumerate(options):
            self.combo.addItem(text)
            self.combo.setItemData(i, lang)
        self.retranslateUi()

    @QtCore.pyqtSlot(int)
    def change_func(self, index):
        data = self.combo.itemData(index)
        if data:
            self.trans.load(data)
            QtWidgets.QApplication.instance().installTranslator(self.trans)
        else:
            QtWidgets.QApplication.instance().removeTranslator(self.trans)

    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.LanguageChange:
            self.retranslateUi()
        super(Demo, self).changeEvent(event)

    def retranslateUi(self):
        self.button.setText(QtWidgets.QApplication.translate("Demo", "Start"))
        self.label.setText(QtWidgets.QApplication.translate("Demo", "Hello, World"))


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

Then generate the .ts:

pylupdate5 main.py  -ts eng-chs.ts
pylupdate5 main.py  -ts eng-fr.ts

Then use Qt Linguist to do the translations.

And finally the .qm:

lrelease eng-fr.ts eng-fr.qm
lrelease eng-chs.ts eng-chs.qm

pyuic

On the other hand, if you are using pyuic5 to convert the .py then if the retranslateUi method is implemented so you can use it:

pyuic5 demo.ui -o demo_ui.py
pylupdate5 demo_ui.py  -ts eng-chs.ts
pylupdate5 demo_ui.py  -ts eng-fr.ts

Then use Qt Linguist to do the translations.

And finally the .qm:

lrelease eng-fr.ts eng-fr.qm
lrelease eng-chs.ts eng-chs.qm

main.py

import sys
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from demo_ui import Ui_Demo

class Demo(QtWidgets.QWidget, Ui_Demo):
    def __init__(self):
        super(Demo, self).__init__()
        self.setupUi(self)

        self.combo.currentIndexChanged.connect(self.change_func)

        self.trans = QtCore.QTranslator(self)

        options = [
            ("English", ""),
            ("français", "eng-fr"),
            ("中文", "eng-chs"),
        ]

        for i, (text, lang) in enumerate(options):
            self.combo.addItem(text)
            self.combo.setItemData(i, lang)
        self.retranslateUi(self)

    @QtCore.pyqtSlot(int)
    def change_func(self, index):
        data = self.combo.itemData(index)
        if data:
            self.trans.load(data)
            QtWidgets.QApplication.instance().installTranslator(self.trans)
        else:
            QtWidgets.QApplication.instance().removeTranslator(self.trans)

    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.LanguageChange:
            self.retranslateUi(self)
        super(Demo, self).changeEvent(event)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())
Friday, August 20, 2021
 
Eduardo Sousa
answered 4 Months ago
95

In order to optionally accept a value, you need to set nargs to '?'. This will make the argument consume one value if it is specified. If the argument is specified but without value, then the argument will be assigned the argument’s const value, so that’s what you need to specify too:

parser = argparse.ArgumentParser()
parser.add_argument('--resize', nargs='?', const=True)

There are now three cases for this argument:

  1. Not specified: The argument will get its default value (None by default):

    >>> parser.parse_args(''.split())
    Namespace(resize=None)
    
  2. Specified without a value: The argument will get its const value:

    >>> parser.parse_args('--resize'.split())
    Namespace(resize=True)
    
  3. Specified with a value: The argument will get the specified value:

    >>> parser.parse_args('--resize 123'.split())
    Namespace(resize='123')
    

Since you are looking for an index, you can also specify type=int so that the argument value will be automatically parsed as an integer. This will not affect the default or const case, so you still get None or True in those cases:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--resize', nargs='?', type=int, const=True)
>>> parser.parse_args('--resize 123'.split())
Namespace(resize=123)

Your usage would then look something like this:

if args.resize is True:
    for object in my_objects:
        object.do_resize()
elif args.resize:
    my_objects[args.resize].do_resize()
Thursday, August 26, 2021
 
scessor
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share