【问题标题】:User input from HTML for use with Python and Selenium用于 Python 和 Selenium 的来自 HTML 的用户输入
【发布时间】:2020-08-16 09:10:46
【问题描述】:

我有一个 python 应用程序,它使用 PySimpleGUI 获取用户输入(名称、日期和文件)、浏览网站并根据给定的输入输入数据。我希望在 pythonanywhere 上托管这个程序,但由于不支持 gui,我需要找到另一种获取用户输入的方法。我创建了一个 HTML 网络表单,但不确定如何继续。

1) 使用request.get 可以获取名称、日期和文件吗?

2) Selenium 不控制通过提交 HTML 表单打开的网页。我需要显式调用浏览器(打开)。由于 Selenium 不绑定到打开的 HTML 页面,因此代码在提交 Web 表单之前执行,我得到一个超时异常。使用之前使用的 GUI,剩下的代码在提交之前不会执行(这是理想的)。

我想要:

  • 使用Selenium控制提交HTML表单打开的网页

  • 在提交 HTML 表单之前停止运行我的代码。提交后,关闭表单并运行代码。

有什么想法吗?

下面我包含了 HTML 文件、我试图开始工作的 Python 代码,以及使用 PySimpleGUI 的程序的相关部分,该部分可以按需要运行。

<!DOCTYPE html>
<html>
<body>

<label for="opt_select">Select an Option:</label>
<select id="opt"
        name="opt_list">
  <option value="AA">AA</option>
  <option value="BB">BB</option>
  <option value="CC">CC</option>
</select>

</body>

<form action="/action_page.php">
  <label>Date:</label>
  <input type="date" id="sum_date" name="sum_start">
</form>
</body>
<form target="_blank" action="http://awebsite"
      method="post" id="submitted_form"
      name="submission" class="validate">
</form>
<form>
  <label for="myfile">Select a file:</label>
  <input type="file" id="myfile" name="myfile"><br><br>
  <input type="submit">
</form>
</html>
    import pandas as pd
    from datetime import datetime
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.action_chains import ActionChains
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    from flask import Flask, render_template, request

    app = Flask(__name__)

    @app.route('/hello', methods=['POST'])
    def hello():
        return render_template('gui.html')

    def user_data():
        data = request.GET['opt_list']

    browser = webdriver.Chrome()
    browser.get('https:/awebsite')
    type(browser)
    delay = 20

    if data == "AA":
        WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'AALanding')))
        browser.find_element_by_id('AALanding').click()
    if data == "BB":
        WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'BBLanding')))
        browser.find_element_by_id('BBLanding').click()
    if data == "CC":
        WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'CCLanding')))
        browser.find_element_by_id('CCLanding').click()

    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=3000)

import tkinter as tk
import time
import pandas as pd
import PySimpleGUI as sg
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

sg.theme('DARKTEAL')
layout = [[sg.Text('Select Student', key='-STUOUTPUT-', font=('Arial', 10))],
          [sg.Combo(['AA', 'BB', 'CC', 'DD'], size=(5, None), font=('Arial', 10),
                    key='-OPT-')],
          [sg.Text('Date to Start Summing', font=('Arial', 10), visible=True),
           sg.In(key='-CAL-', size=(12, None), default_text='MM/DD/YYYY')],
          [sg.CalendarButton('Calendar', key='-OUTPUT-', target='-CAL-', pad=None, size=(10, None), font=('Arial', 10),
                             format='%m/%d/%Y')],
          [sg.Text('Filename', key='-FOUTPUT-', font=('Arial', 10))],
          [sg.In(visible=False),
           sg.Input(key='-DIR-', size=(20, None)),
           sg.FileBrowse('Browse', target='-DIR-', font=('Arial', 10))],
          [sg.OK(font=('Arial', 10)), sg.Cancel(font=('Arial', 10))]]

window = sg.Window('Data Collector', layout, grab_anywhere=False, size=(400, 280), return_keyboard_events=True,
                   finalize=True)

event, values = window.read()
window['-STUOUTPUT-'](values['-STUIN-'])
window['-OUTPUT-'](values['-CAL-'])
window['-FOUTPUT-'](values['-DIR-'])
acedate = (values['-CAL-'])
opt = (values['-OPT-'])
file = (values['-DIR-'])
window.close()

browser = webdriver.Chrome()
browser.get('awebsite')
type(browser)

delay = 20

df = pd.read_excel(file, Sheet_name=0, header=None)

def bx_select():
    if data == "AA":
    WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'AALanding')))
    browser.find_element_by_id('AALanding').click()
if data == "BB":
    WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'BBLanding')))
    browser.find_element_by_id('BBLanding').click()
if data == "CC":
    WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'CCLanding')))
    browser.find_element_by_id('CCLanding').click()

def clear():
    ActionChains(browser) \
        .send_keys(Keys.CLEAR) \
        .perform()
def tab():
    ActionChains(browser) \
        .send_keys(Keys.TAB) \
        .perform()
def enter():
    ActionChains(browser) \
        .send_keys(Keys.ENTER) \
        .perform()
def page_up():
    ActionChains(browser) \
        .send_keys(Keys.CONTROL + Keys.HOME) \
        .perform()

bx_select()

clear()


def autosum():
    # length of bx measures
    x = len(df.columns)
    # used to determine when at end of row
    z = 1
    # location of column to start summing
    b = 1
    # number of days in the month
    c = len(df.index)
    # used to stop once last day of month reached
    y = 1
    # slices date chosen from calendar (dd) to determine where to start summing
    n = int(values['-CAL-'][3:5])
    # today's date (used to stop once current day is reached)
    d = datetime.today().strftime('%Y-%m-%d')

    while n < c:
        while z < x:
            m = df.iloc[n, b]
            z = z + 1
            b = b + 1
            if pd.isnull(m):
                tab()
                continue
            else:
                ActionChains(browser) \
                    .send_keys(str(m)) \
                    .perform()
            if z == x:
                n = n + 1
                y = y + 1
                z = 1
                b = 1
                enter()
                page_up()
                if n == c or str(pd.to_datetime(df.iloc[n, 0]).date()) == d:
                    return
                WebDriverWait(browser, delay).until(EC.visibility_of_element_located(
                    (By.CSS_SELECTOR,
                     'div.ZForm:nth-child(5) > div:nth-child(1) > div:nth-child(1) > h5:nth-child(1)')))
                bx_select()
                clear()
            else:
                tab()
                time.sleep(0.5)
autosum()

【问题讨论】:

  • gui.html 文件上方的那个 HTML 吗?
  • 顶部的代码是位于名为 gui.html 的文件中的 HTML
  • 你确定 chrome 浏览器会在 python Anywhere 服务器上运行吗?
  • 貌似pythonanywhere只支持火狐,heroku支持Chrome
  • PythonAnywhere dev here -- 我们正在运行一个测试版,您可以在其中将 Chrome 支持添加到您的帐户中。只需在登录我们的网站时使用“发送反馈”链接给我们留言,我们就可以为您打开它。

标签: python html selenium selenium-webdriver


【解决方案1】:

所以在我看来,这个问题更多的是关于 Flask,而不是 selenium 或 HTML。您似乎希望允许用户在 HTML 表单上输入数据,并让该表单在您的 python 脚本中调用某些函数。你可以做到这一点并不难。我相信this question 可以很好地解决您的问题。

一旦您的表单调用了您想要的脚本,您就可以使用该方法上的输入数据来启动 selenium 并让它在所需的位置输入您的数据。

这是你要找的吗?

【讨论】:

    【解决方案2】:

    回答1)

    您需要修复 HTML 文件并将所有输入字段(您需要的那些在下面的 process_form() 中)放在同一个 &lt;form action="..."&gt; 标记中,指向您的 Flask 提交处理程序(见下文)。例如,如果要处理“opt_list”,则需要将其移动到&lt;form&gt; 标记下。我还建议使用 POST 方法(而不是 GET)。所以 gui.html 的结构应该是这样的:

    <!DOCTYPE html>
    <html>
    <body>
    <form action="/process_url" method="post" enctype="multipart/form-data">
      <label for="opt_select">Select an Option:</label>
      <select id="opt"
            name="opt_list">
        <option value="AA">AA</option>
        <option value="BB">BB</option>
        <option value="CC">CC</option>
      </select>
      <br/>
      <label>Date:</label>
      <input type="date" id="sum_date" name="sum_start">
      <br/>
      <label for="myfile">Select a file:</label>
      <input type="file" id="myfile" name="myfile"><br><br>
      <input type="submit">
    </form>
    </html>
    

    回答2)

    您需要将 Selenium 代码移动到仅在提交表单时调用的函数中(而不是在未缩进的脚本正文中)。

    from flask import Flask, render_template, request
    
    app = Flask(__name__)
    app.config['MAX_CONTENT_LENGTH'] = 1 * 1024 * 1024
    
    
    # This is the Flask handler to show your form
    @app.route('/', methods=['GET'])
    def hello():
        return render_template('gui.html')
    
    # Add a Flask handler to process your form submission.
    # (You can also use POST method instead of GET if you don't
    # want your form content to show in the address bar)
    @app.route('/process_url', methods=['POST'])  
    def process_form():
        # Read form values
        opt = request.form['opt_list']
        sum_start = request.form['sum_start']
        myfile = request.files['myfile']
        file_content = myfile.stream.read().decode('utf-8', 'ignore')
        # Do Work
        my_work(opt, sum_start, file_content)
        # Return an HTML output of your results
        html = f"""
        <html>
          <body>
            <h3>Result page</h3>
            opt: {opt}<br/>
            sum_start: {sum_start}<br/>
            myfile.filename: {myfile.filename}<br/>
            myfile.stream: <br/>
            <pre>{file_content}</pre>
          </body>
        </html>
        """
        return html
    
    def my_work(opt, sum_start, file_content):
      # TODO: Put your Selenium code here 
      pass
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=3000, debug=True)
    

    此外,请尽量避免 Selenium 代码的长时间执行,以防止浏览器超时。

    有了这些指导方针,我希望你能够解决你的问题。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多