Spaces:
Paused
Paused
prabinpanta0
commited on
Commit
•
85c5f42
1
Parent(s):
263299d
Completed the framework
Browse files- Dockerfile +28 -0
- README.md +0 -1
- app.py +47 -0
- form_filler.py +128 -0
- requirements.txt +4 -0
- static/script.js +50 -0
- templates/index.html +41 -0
Dockerfile
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use an official Python runtime as a parent image
|
2 |
+
FROM python:3.8-slim
|
3 |
+
|
4 |
+
# Set environment variables
|
5 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
6 |
+
ENV PYTHONUNBUFFERED=1
|
7 |
+
|
8 |
+
# Set the working directory
|
9 |
+
WORKDIR /app
|
10 |
+
|
11 |
+
# Install system dependencies
|
12 |
+
RUN apt-get update && apt-get install -y \
|
13 |
+
xvfb \
|
14 |
+
x11-xserver-utils \
|
15 |
+
chromium-driver
|
16 |
+
|
17 |
+
# Install Python dependencies
|
18 |
+
COPY requirements.txt /app/
|
19 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
20 |
+
|
21 |
+
# Copy the application code
|
22 |
+
COPY . /app/
|
23 |
+
|
24 |
+
# Expose port 5000 for Flask
|
25 |
+
EXPOSE 5000
|
26 |
+
|
27 |
+
# Command to run the application
|
28 |
+
CMD ["python", "app.py"]
|
README.md
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
# GHM
|
|
|
|
app.py
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, render_template, request, jsonify
|
2 |
+
from form_filler import FormFiller
|
3 |
+
import threading
|
4 |
+
|
5 |
+
app = Flask(__name__)
|
6 |
+
form_filler = FormFiller()
|
7 |
+
|
8 |
+
@app.route('/')
|
9 |
+
def index():
|
10 |
+
return render_template('index.html')
|
11 |
+
|
12 |
+
@app.route('/start', methods=['POST'])
|
13 |
+
def start_form_filling():
|
14 |
+
url = request.json['url']
|
15 |
+
iterations = int(request.json['iterations'])
|
16 |
+
|
17 |
+
def run_form_filler():
|
18 |
+
form_filler.fill_form_in_parallel(url, iterations)
|
19 |
+
|
20 |
+
form_filler.total_iterations = iterations
|
21 |
+
form_filler.iterations_left = iterations
|
22 |
+
form_filler.responses_sent = 0
|
23 |
+
form_filler.errors = 0
|
24 |
+
form_filler.environment_status = []
|
25 |
+
|
26 |
+
thread = threading.Thread(target=run_form_filler)
|
27 |
+
thread.start()
|
28 |
+
|
29 |
+
return jsonify({"message": "Form filling started"})
|
30 |
+
|
31 |
+
@app.route('/stop', methods=['POST'])
|
32 |
+
def stop_form_filling():
|
33 |
+
form_filler.stop()
|
34 |
+
return jsonify({"message": "Form filling stopped"})
|
35 |
+
|
36 |
+
@app.route('/status', methods=['GET'])
|
37 |
+
def get_status():
|
38 |
+
return jsonify({
|
39 |
+
"total_iterations": form_filler.total_iterations,
|
40 |
+
"responses_sent": form_filler.responses_sent,
|
41 |
+
"errors": form_filler.errors,
|
42 |
+
"iterations_left": form_filler.iterations_left,
|
43 |
+
"environment_status": form_filler.environment_status
|
44 |
+
})
|
45 |
+
|
46 |
+
if __name__ == '__main__':
|
47 |
+
app.run(host='0.0.0.0', port=5000)
|
form_filler.py
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import random
|
3 |
+
from concurrent.futures import ThreadPoolExecutor
|
4 |
+
import time
|
5 |
+
import os
|
6 |
+
from selenium import webdriver
|
7 |
+
from selenium.webdriver.chrome.options import Options
|
8 |
+
from selenium.webdriver.common.by import By
|
9 |
+
from xvfbwrapper import Xvfb
|
10 |
+
from threading import Lock, Event
|
11 |
+
|
12 |
+
class FormFiller:
|
13 |
+
def __init__(self):
|
14 |
+
self.total_iterations = 0
|
15 |
+
self.responses_sent = 0
|
16 |
+
self.errors = 0
|
17 |
+
self.iterations_left = 0
|
18 |
+
self.stop_flag = Event()
|
19 |
+
self.lock = Lock()
|
20 |
+
self.environment_status = []
|
21 |
+
|
22 |
+
def fill_form(self, url, num_iterations, update_callback=None, environment_id=1):
|
23 |
+
self.stop_flag.clear()
|
24 |
+
display = None
|
25 |
+
driver = None
|
26 |
+
|
27 |
+
try:
|
28 |
+
# Start Xvfb display
|
29 |
+
display = Xvfb(width=1280, height=720)
|
30 |
+
display.start()
|
31 |
+
|
32 |
+
chrome_options = Options()
|
33 |
+
chrome_options.add_argument("--headless")
|
34 |
+
chrome_options.add_argument("--no-sandbox")
|
35 |
+
chrome_options.add_argument("--disable-dev-shm-usage")
|
36 |
+
chrome_options.add_argument("--disable-gpu")
|
37 |
+
|
38 |
+
driver = webdriver.Chrome(options=chrome_options)
|
39 |
+
driver.get(url)
|
40 |
+
|
41 |
+
for _ in range(num_iterations):
|
42 |
+
if self.stop_flag.is_set():
|
43 |
+
break
|
44 |
+
|
45 |
+
try:
|
46 |
+
# Handling radio buttons
|
47 |
+
radio_buttons = driver.find_elements(By.CSS_SELECTOR, 'div[role="radiogroup"]')
|
48 |
+
for radio_group in radio_buttons:
|
49 |
+
options = radio_group.find_elements(By.CSS_SELECTOR, 'div[role="radio"]')
|
50 |
+
random.choice(options).click()
|
51 |
+
|
52 |
+
# Handling checkboxes
|
53 |
+
checkboxes = driver.find_elements(By.CSS_SELECTOR, 'div[role="checkbox"]')
|
54 |
+
for checkbox in checkboxes:
|
55 |
+
if random.choice([True, False]):
|
56 |
+
checkbox.click()
|
57 |
+
|
58 |
+
# Handling multiple choice grids
|
59 |
+
grids = driver.find_elements(By.CSS_SELECTOR, 'div[role="grid"]')
|
60 |
+
for grid in grids:
|
61 |
+
rows = grid.find_elements(By.CSS_SELECTOR, 'div[role="row"]')
|
62 |
+
for row in rows:
|
63 |
+
options = row.find_elements(By.CSS_SELECTOR, 'div[role="radio"]')
|
64 |
+
random.choice(options).click()
|
65 |
+
|
66 |
+
# Submit the form
|
67 |
+
submit = driver.find_element(By.CSS_SELECTOR, 'div[role="button"][aria-label="Submit"]')
|
68 |
+
submit.click()
|
69 |
+
|
70 |
+
logging.info(f"Form submitted successfully by Environment {environment_id}")
|
71 |
+
|
72 |
+
with self.lock:
|
73 |
+
self.responses_sent += 1
|
74 |
+
self.iterations_left = self.total_iterations - self.responses_sent
|
75 |
+
self.environment_status.append(
|
76 |
+
f"Environment {environment_id}: Total Responses Sent: {self.responses_sent}, Errors: {self.errors}, Iterations Left: {self.iterations_left}"
|
77 |
+
)
|
78 |
+
|
79 |
+
# Wait and reload the form
|
80 |
+
time.sleep(5)
|
81 |
+
driver.get(url)
|
82 |
+
|
83 |
+
except Exception as e:
|
84 |
+
with self.lock:
|
85 |
+
self.errors += 1
|
86 |
+
self.iterations_left = self.total_iterations - self.responses_sent
|
87 |
+
self.environment_status.append(
|
88 |
+
f"Environment {environment_id}: Error occurred: {e}"
|
89 |
+
)
|
90 |
+
logging.error(f"Error occurred in Environment {environment_id}: {e}")
|
91 |
+
|
92 |
+
finally:
|
93 |
+
if driver:
|
94 |
+
driver.quit()
|
95 |
+
if display:
|
96 |
+
if 'DISPLAY' in os.environ:
|
97 |
+
display.stop()
|
98 |
+
|
99 |
+
def stop(self):
|
100 |
+
self.stop_flag.set()
|
101 |
+
|
102 |
+
def fill_form_in_parallel(self, url, total_iterations, update_callback=None):
|
103 |
+
self.total_iterations = total_iterations
|
104 |
+
self.iterations_left = total_iterations
|
105 |
+
self.responses_sent = 0
|
106 |
+
self.errors = 0
|
107 |
+
self.environment_status = []
|
108 |
+
|
109 |
+
num_envs = 10 # Total number of environments to run concurrently
|
110 |
+
iterations_per_env = total_iterations // num_envs # Each environment should process its share of iterations
|
111 |
+
|
112 |
+
with ThreadPoolExecutor(max_workers=num_envs) as executor:
|
113 |
+
futures = []
|
114 |
+
for i in range(num_envs):
|
115 |
+
futures.append(executor.submit(self.fill_form, url, iterations_per_env, update_callback, i + 1))
|
116 |
+
|
117 |
+
for future in futures:
|
118 |
+
future.result()
|
119 |
+
|
120 |
+
# Handle remaining iterations
|
121 |
+
remaining_iterations = total_iterations % num_envs
|
122 |
+
if remaining_iterations > 0:
|
123 |
+
with ThreadPoolExecutor(max_workers=remaining_iterations) as executor:
|
124 |
+
futures = []
|
125 |
+
for i in range(remaining_iterations):
|
126 |
+
futures.append(executor.submit(self.fill_form, url, 1, update_callback, i + 1))
|
127 |
+
for future in futures:
|
128 |
+
future.result()
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Flask
|
2 |
+
selenium
|
3 |
+
flask
|
4 |
+
xvfbwrapper
|
static/script.js
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
document.addEventListener('DOMContentLoaded', () => {
|
2 |
+
const form = document.getElementById('form-filler-form');
|
3 |
+
const startButton = document.getElementById('start-button');
|
4 |
+
const stopButton = document.getElementById('stop-button');
|
5 |
+
const statusDiv = document.getElementById('status');
|
6 |
+
|
7 |
+
let intervalId;
|
8 |
+
|
9 |
+
form.addEventListener('submit', async (e) => {
|
10 |
+
e.preventDefault();
|
11 |
+
const url = document.getElementById('url').value;
|
12 |
+
const iterations = document.getElementById('iterations').value;
|
13 |
+
|
14 |
+
startButton.disabled = true;
|
15 |
+
stopButton.disabled = false;
|
16 |
+
|
17 |
+
await fetch('/start', {
|
18 |
+
method: 'POST',
|
19 |
+
headers: {
|
20 |
+
'Content-Type': 'application/json',
|
21 |
+
},
|
22 |
+
body: JSON.stringify({ url, iterations }),
|
23 |
+
});
|
24 |
+
|
25 |
+
intervalId = setInterval(updateStatus, 1000);
|
26 |
+
});
|
27 |
+
|
28 |
+
stopButton.addEventListener('click', async () => {
|
29 |
+
await fetch('/stop', { method: 'POST' });
|
30 |
+
startButton.disabled = false;
|
31 |
+
stopButton.disabled = true;
|
32 |
+
clearInterval(intervalId);
|
33 |
+
});
|
34 |
+
|
35 |
+
async function updateStatus() {
|
36 |
+
const response = await fetch('/status');
|
37 |
+
const data = await response.json();
|
38 |
+
|
39 |
+
statusDiv.innerHTML = `
|
40 |
+
<p>Total Iterations: ${data.total_iterations}</p>
|
41 |
+
<p>Responses Sent: ${data.responses_sent}</p>
|
42 |
+
<p>Errors: ${data.errors}</p>
|
43 |
+
<p>Iterations Left: ${data.iterations_left}</p>
|
44 |
+
<h3>Environment Status:</h3>
|
45 |
+
<ul>
|
46 |
+
${data.environment_status.map(status => `<li>${status}</li>`).join('')}
|
47 |
+
</ul>
|
48 |
+
`;
|
49 |
+
}
|
50 |
+
});
|
templates/index.html
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Form Filler</title>
|
7 |
+
<style>
|
8 |
+
body {
|
9 |
+
font-family: Arial, sans-serif;
|
10 |
+
max-width: 800px;
|
11 |
+
margin: 0 auto;
|
12 |
+
padding: 20px;
|
13 |
+
}
|
14 |
+
form {
|
15 |
+
margin-bottom: 20px;
|
16 |
+
}
|
17 |
+
input, button {
|
18 |
+
margin: 10px 0;
|
19 |
+
padding: 5px;
|
20 |
+
}
|
21 |
+
#status {
|
22 |
+
border: 1px solid #ccc;
|
23 |
+
padding: 10px;
|
24 |
+
margin-top: 20px;
|
25 |
+
}
|
26 |
+
</style>
|
27 |
+
</head>
|
28 |
+
<body>
|
29 |
+
<h1>Form Filler</h1>
|
30 |
+
<form id="form-filler-form">
|
31 |
+
<label for="url">Form URL:</label><br>
|
32 |
+
<input type="url" id="url" name="url" required><br>
|
33 |
+
<label for="iterations">Number of Iterations:</label><br>
|
34 |
+
<input type="number" id="iterations" name="iterations" required><br>
|
35 |
+
<button type="submit" id="start-button">Start</button>
|
36 |
+
</form>
|
37 |
+
<button id="stop-button" disabled>Stop</button>
|
38 |
+
<div id="status"></div>
|
39 |
+
<script src="/static/script.js"></script>
|
40 |
+
</body>
|
41 |
+
</html>
|