Как установить значение ввода (тип = файл) с помощью QWebElement?

Я пытаюсь загрузить фото на vk.com с помощью модуль QtWebKit. Проблема, с которой я столкнулся, заключается в невозможности правильно заполнить значение input(type="file"). Вот некоторый связанный код, который я использую:

def upload():
    print 'uploading...'
    photoInput = web.page().mainFrame().documentElement().findFirst('input[id="photos_upload_input"]')
    assert photoInput, 'No input found'
    photoInput.setAttribute('value', '/Users/elmigranto/Downloads/stuff.png')

    print photoInput.evaluateJavaScript('return this.value;').toString()

Разумно отметить, что заполнение значения файлового ввода невозможно из Javascript из-за политики безопасности браузера. Однако это должно быть возможно с использованием Qt API, а именно QWebElement:: setAttribute(). Что я и сделал… безрезультатно (ну, photoInput.attribute('value') возвращает ожидаемый результат, а photoInput.evaluateJavaScript('return this.value;').toString() возвращает пустую строку, обработчик ввода onchange тоже не срабатывает).

Установка других атрибутов не проблема, например, QWebElement::addClass() прекрасно работает.

Любая помощь будет очень кстати.
Спасибо.


person Aleksei Zabrodskii    schedule 06.03.2013    source источник


Ответы (1)


Метод setAttribute может по-прежнему не работать из соображений безопасности.

Но вы можете переопределить функцию QWebPage::chooseFile, которая обычно должна открывать диалоговое окно загрузки и возвращать имя файла, чтобы она возвращала статическое имя файла, не открывая диалоговое окно, и активировать эту загрузку, имитируя нажатие клавиши «возврат» на элементе ввода.

Кажется, это работает:

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

class WebPage(QWebPage):
    def __init__(self, parent = None):
        super(WebPage, self).__init__(parent)
        self.overrideUpload = None

    def chooseFile(self, originatingFrame, oldFile):
        if self.overrideUpload is None:
            return super(WebPage, self).chooseFile(originatingFrame, oldFile)
        result = self.overrideUpload
        self.overrideUpload = None
        return result

    def setUploadFile(self, selector, filename):
        button = self.mainFrame().documentElement().findFirst(selector)
        self.overrideUpload = filename
        # set the focus on the input element
        button.setFocus();
        # and simulate a keypress event to make it call our chooseFile method 
        webview.event(QKeyEvent(QEvent.KeyPress, Qt.Key_Enter, Qt.NoModifier))

def upload():
    print 'uploading...'    
    page.setUploadFile('input[id="photos_upload_input"]',
        '/Users/elmigranto/Downloads/stuff.png') 
    # The change seems to be asynchronous, at it isn't visible 
    # just after the previous call

app = QApplication(sys.argv)
webview = QWebView()
page = WebPage(webview)
webview.setPage(page)
source = '''
<form action="#">
  Select a file: <input type="file" id="photos_upload_input">
  <input type="submit">
</form>
'''
webview.loadFinished.connect(upload)
webview.show()
webview.setHtml(source)
sys.exit(app.exec_())
person alexisdm    schedule 16.03.2013
comment
Как webview.event(QKeyEvent(QEvent.KeyPress, Qt.Key_Enter, Qt.NoModifier)) будет переведен в его эквивалент C++? - person hytromo; 19.10.2013
comment
@ user9379 Это должно работать: QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); webview->event(&keyEvent);. - person alexisdm; 21.10.2013
comment
Могу ли я сделать это, используя WebKit.NET или CefSharp? Я много ищу, но не могу найти объект, эквивалентный методу QWebPage или setPage() - person Jack; 04.09.2015
comment
@Jack Вам действительно нужно имитировать пользовательский ввод? Разве вы не можете создать запрос POST вручную с помощью HttpWebRequest? (например, это) - person alexisdm; 04.09.2015
comment
@alexisdm: не обращайте внимания на предыдущий комментарий, как мне установить тип ввода = файл, открытый на текущей странице? - person Jack; 05.09.2015