Seite 1 von 1

subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Mittwoch 13. April 2011, 12:19
von alexPython
Hallo,
wie funktioniert das mit dem Rückgabewert?
Ziel ist es, dass das aufgerufene Programm einen String zurück gibt,
bwz. ist es möglich ein Bild UND einen Text zurück zugeben?
(gleichzeitig)

Code: Alles auswählen

p = subprocess.Popen(options,0,stdout=subprocess.PIPE)
output,errors = p.communicate()
mein Englisch ist nicht ausreichend für die Dokumentation und in
Deutsch habe ich nichts brauchbares gefunden.

Gruß

Re: subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Mittwoch 13. April 2011, 12:33
von BlackJack
@alexPython: `output` enthält danach alles, was der Prozess über seine Standardausgabe geschrieben hat. Und das kann im Grunde alles sein, was sich irgendwie als Bytes kodieren lässt.

Re: subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Mittwoch 13. April 2011, 13:20
von alexPython
und wie schreibe ich was in die Standardausgabe?

Ich habe folgendes Programm

Code: Alles auswählen

#!/usr/bin/env python
#
# webkit2png.py
#
# Creates screenshots of webpages using by QtWebkit.
#
# Copyright (c) 2008 Roland Tapken <roland@dau-sicher.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

import sys
import signal
import os
import logging
import time

from optparse import OptionParser

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import QWebPage

# Class for Website-Rendering. Uses QWebPage, which
# requires a running QtGui to work.
class WebkitRenderer(QObject):

    # Initializes the QWebPage object and registers some slots
    def __init__(self):
        logging.debug("Initializing class %s", self.__class__.__name__)
        self._page = QWebPage()
        
        
        self.connect(self._page, SIGNAL("loadFinished(bool)"), self.__on_load_finished)
        self.connect(self._page, SIGNAL("loadStarted()"), self.__on_load_started)

        # The way we will use this, it seems to be unesseccary to have Scrollbars enabled
        self._page.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        self._page.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

        # Helper for multithreaded communication through signals 
        self.__loading = False
        self.__loading_result = False

    # Loads "url" and renders it.
    # Returns QImage-object on success.
    def render(self, url, width=0, height=0, timeout=0):
        logging.debug("render(%s, timeout=%d)", url, timeout)

        # This is an event-based application. So we have to wait until
        # "loadFinished(bool)" raised.
        cancelAt = time.time() + timeout
        self._page.mainFrame().load(QUrl(url))
        while self.__loading:
            if timeout > 0 and time.time() >= cancelAt:
                raise RuntimeError("Request timed out")
            QCoreApplication.processEvents()

        logging.debug("Processing result")

        if self.__loading_result == False:
            raise RuntimeError("Failed to load %s" % url)

        # Set initial viewport (the size of the "window")
        size = self._page.mainFrame().contentsSize()
        if width > 0:
            size.setWidth(width)
        if height > 0:
            size.setHeight(height)
        self._page.setViewportSize(size)

        # Paint this frame into an image
        image = QImage(self._page.viewportSize(), QImage.Format_ARGB32)
        painter = QPainter(image)
        self._page.mainFrame().render(painter)
        painter.end()
        
        #document = self._page.mainFrame().documentElement()
        #document.findAll("a")
        
        
        return image


    # Eventhandler for "loadStarted()" signal
    def __on_load_started(self):
        logging.debug("loading started")
        self.__loading = True

    # Eventhandler for "loadFinished(bool)" signal
    def __on_load_finished(self, result):
        logging.debug("loading finished with result %s", result)
        self.__loading = False
        self.__loading_result = result


if __name__ == '__main__':
    # Parse command line arguments.
    # Syntax:
    # $0 [--xvfb|--display=DISPLAY] [--debug] [--output=FILENAME] <URL>
    qtargs = [sys.argv[0]]

    description = "Creates a screenshot of a website using QtWebkit." \
                + "This program comes with ABSOLUTELY NO WARRANTY. " \
                + "This is free software, and you are welcome to redistribute " \
                + "it under the terms of the GNU General Public License v2."

    parser = OptionParser(usage="usage: %prog [options] <URL>",
                          version="%prog 0.1, Copyright (c) 2008 Roland Tapken",
                          description=description)
    parser.add_option("-x", "--xvfb", action="store_true", dest="xvfb",
                      help="Start an 'xvfb' instance.", default=False)
    parser.add_option("-g", "--geometry", dest="geometry", nargs=2, default=(0, 0), type="int",
                      help="Geometry of the virtual browser window (0 means 'autodetect') [default: %default].", metavar="WIDTH HEIGHT")
    parser.add_option("-o", "--output", dest="output",
                      help="Write output to FILE instead of STDOUT.", metavar="FILE")
    parser.add_option("-f", "--format", dest="format", default="png",
                      help="Output image format [default: %default]", metavar="FORMAT")
    parser.add_option("--scale", dest="scale", nargs=2, type="int",
                      help="Scale the image to this size", metavar="WIDTH HEIGHT")
    parser.add_option("--aspect-ratio", dest="ratio", type="choice", choices=["ignore", "keep", "expand"],
                      help="One of 'ignore', 'keep' or 'expand' [default: %default]")
    parser.add_option("-t", "--timeout", dest="timeout", default=0, type="int",
                      help="Time before the request will be canceled [default: %default]", metavar="SECONDS")
    parser.add_option("-d", "--display", dest="display",
                      help="Connect to X server at DISPLAY.", metavar="DISPLAY")
    parser.add_option("--debug", action="store_true", dest="debug",
                      help="Show debugging information.", default=False)
    
    # Parse command line arguments and validate them (as far as we can)
    (options,args) = parser.parse_args()
    if len(args) != 1:
        parser.error("incorrect number of arguments")
    if options.display and options.xvfb:
        parser.error("options -x and -d are mutually exclusive")
    options.url = args[0]

    # Enable output of debugging information
    if options.debug:
        logging.basicConfig(level=logging.DEBUG)

    # Add display information for qt (you may also use the environment var DISPLAY)
    if options.display:
        qtargs.append("-display")
        qtargs.append(options.display)

    if options.xvfb:
        # Start 'xvfb' instance by replacing the current process
        newArgs = ["xvfb-run", "--server-args=-screen 0, 640x480x24", sys.argv[0]]
        for i in range(1, len(sys.argv)):
            if sys.argv[i] not in ["-x", "--xvfb"]:
                newArgs.append(sys.argv[i])
        logging.debug("Executing %s" % " ".join(newArgs))
        os.execvp(newArgs[0], newArgs)
        raise RuntimeError("Failed to execute '%s'" % newArgs[0])

    # Prepare outout ("1" means STDOUT)
    if options.output == None:
        qfile = QFile()
        qfile.open(1, QIODevice.WriteOnly)
        #options.output = qfile
        
    options.output = "baljgaljgblabj"
        
         
    # Initialize Qt-Application, but make this script
    # abortable via CTRL-C
    app = QApplication(qtargs)
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    # Initialize WebkitRenderer object
    renderer = WebkitRenderer()

    # Technically, this is a QtGui application, because QWebPage requires it
    # to be. But because we will have no user interaction, and rendering can
    # not start before 'app.exec_()' is called, we have to trigger our "main"
    # by a timer event.
    def __on_exec():
        # Render the page.
        # If this method times out or loading failed, a
        # RuntimeException is thrown
        try:
            image = renderer.render(options.url, 
                                    width=options.geometry[0], 
                                    height=options.geometry[1], 
                                    timeout=options.timeout)

            if options.scale:
                # Scale this image
                if options.ratio == 'keep':
                    ratio = Qt.KeepAspectRatio
                elif options.ratio == 'expand':
                    ratio = Qt.KeepAspectRatioByExpanding
                else:
                    ratio = Qt.IgnoreAspectRatio
                image = image.scaled(options.scale[0], options.scale[1], ratio)

            image.save(options.output, options.format)
           
            
            if isinstance(options.output, QFile):
                options.output.close()
            sys.exit(0)
        except RuntimeError, e:
            logging.error(e.message)
            sys.exit(1)

    # Go to main loop (required)
    QTimer().singleShot(0, __on_exec)
    sys.exit(app.exec_())

das bild wird mit image.save(options.output, options.format) geschrieben.
Wie füge ich dem Output was hinzu?

Gruß

Re: subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Mittwoch 13. April 2011, 13:48
von BlackJack
@alexPython: Die Standardausgabe stellt Python als Dateiobjekt zur Verfügung: `sys.stdout`.

Re: subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Mittwoch 13. April 2011, 14:02
von alexPython
ja danke, ich habs gefunden.

Code: Alles auswählen

sys.stdout.write("bla und") 
image.save(options.output, options.format)
ich will text und ein bild zurückgeben.
req.content_type = "image/png"
req.write(output)

gibt es die möglichkeit auf die zwei rückgaben zu zu greifen?
ala output(0) -> bild
output(1) -> text

Re: subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Mittwoch 13. April 2011, 14:25
von lunar
Nein. Ein Prozess hat eine Standardausgabe, auf der genau ein Bytestrom ausgeben werden kann.

Re: subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Mittwoch 13. April 2011, 15:25
von BlackJack
@alexPython: Genau wie Funktionen in Python nur *einen* Wert zurückgeben können, gibt es wie lunar schon gesagt hat nur einen Bytestrom den man über `stdout` ausgeben kann. Aber genau so wie der eine Rückgabewert bei einer Python-Funktion auch ein zusammengesetzter Datentyp sein kann, wie zum Beispiel ein Tupel, eine Liste, ein Wörterbuch, oder ein anderes komplexeres Objekt, kannst Du auch mehr als ein "Objekt" in einem Bytestrom kodieren. Du musst das auf der anderen Seite beim Empfang halt nur wieder in die Einzelbestandteile zerlegen können.

Re: subprocess.Popen() -> Rückgabewert ermitteln

Verfasst: Donnerstag 14. April 2011, 08:38
von alexPython
Hallo,

ja ich habe es bemerkt.
Die Werte sind mit Komma getrennt.

Gruß