Skip to content

Commit 0d891f9

Browse files
add-FormAction (#50)
* add-FormAction * add documentation * add documentation * change FormAction to FillForm * add some check in fill_form * Update fill_form.js * Har support * Remove excess --------- Co-authored-by: matthew <[email protected]>
1 parent cf90be7 commit 0d891f9

File tree

4 files changed

+83
-6
lines changed

4 files changed

+83
-6
lines changed

README.md

+26-1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,31 @@ Example request body:
153153
}
154154
```
155155

156+
### **/har**
157+
This POST method allows to get the HAR file
158+
159+
### **/form_action**
160+
This POST method allows filling out and submitting forms on a webpage by interacting with input elements identified by CSS selectors. It also allows clicking a submit button if specified.
161+
162+
Example request body:
163+
164+
```json5
165+
{
166+
"inputMapping": { // A dictionary where each key is a CSS selector, and each value is another dictionary containing details about the input for that element.
167+
"input[name='username']": {
168+
"value": "myUsername",
169+
"delay": 100
170+
},
171+
"input[name='password']": {
172+
"value": "myPassword",
173+
"delay": 100
174+
}
175+
},
176+
"submitButton": "button[type='submit']" //<string> (optional) The CSS selector for the form's submit button. If provided, the button will be clicked after filling in the form.
177+
}
178+
```
179+
180+
156181
### **/action**
157182

158183
Body of this POST request should be a js code that declares function action with at least page
@@ -250,5 +275,5 @@ Once you don't need the browser tab you need to explicitly close it (e.g. at the
250275
- [x] proxy support for puppeteer
251276
- [x] support of extra headers
252277
- [x] error handling for requests
253-
- [ ] har support
278+
- [x] har support
254279
- [x] scaling to several docker containers

app.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const {createPuppeteerMetrics} = require('./helpers/meter'); // Essential to put it first
1+
const { createPuppeteerMetrics } = require('./helpers/meter'); // Essential to put it first
22

33
const express = require('express');
44
const puppeteer = require('puppeteer-extra')
@@ -21,6 +21,7 @@ const screenshotRouter = require('./routes/screenshot');
2121
const recaptchaSolverRouter = require('./routes/recaptcha_solver')
2222
const mhtmlRouter = require('./routes/mhtml');
2323
const harRouter = require('./routes/har');
24+
const fillFormRouter = require('./routes/fill_form');
2425
const closeContextRouter = require('./routes/close_context');
2526

2627
const middlewares = require('./helpers/middlewares');
@@ -78,7 +79,7 @@ async function setupBrowser() {
7879
const browser = await puppeteer.launch(
7980
{
8081
headless: HEADLESS,
81-
defaultViewport: {width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT},
82+
defaultViewport: { width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT },
8283
timeout: CONNECT_TIMEOUT
8384
});
8485
browser.on('disconnected', setupBrowser);
@@ -96,9 +97,9 @@ async function setupBrowser() {
9697
})();
9798

9899
app.use(express.json());
99-
app.use(express.urlencoded({extended: false}));
100+
app.use(express.urlencoded({ extended: false }));
100101
app.use(middlewares.logHTTPMiddleware());
101-
app.use(bodyParser.raw({inflate: true, limit: '200kb', type: 'application/javascript'}));
102+
app.use(bodyParser.raw({ inflate: true, limit: '200kb', type: 'application/javascript' }));
102103
app.use(cookieParser());
103104

104105
app.use('/', indexRouter);
@@ -113,6 +114,7 @@ app.use('/screenshot', screenshotRouter);
113114
app.use('/recaptcha_solver', recaptchaSolverRouter);
114115
app.use('/mhtml', mhtmlRouter);
115116
app.use('/har', harRouter);
117+
app.use('/fill_form', fillFormRouter);
116118
app.use('/close_context', closeContextRouter);
117119

118120
app.use(middlewares.processExceptionMiddleware);

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "scrapy-puppeteer-service",
3-
"version": "0.3.3",
3+
"version": "0.3.4",
44
"private": true,
55
"scripts": {
66
"start": "node ./bin/www"

routes/fill_form.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
const express = require('express');
2+
const utils = require('../helpers/utils');
3+
const router = express.Router();
4+
5+
async function action(page, request) {
6+
const inputMapping = request.body.inputMapping;
7+
const submitButton = request.body.submitButton;
8+
9+
for (const [selector, params] of Object.entries(inputMapping)) {
10+
const value = params.value;
11+
const delay = params.delay || 0;
12+
await page.type(selector, value, { delay });
13+
}
14+
15+
if (submitButton) {
16+
await page.click(submitButton);
17+
}
18+
19+
return await utils.getContents(page);
20+
21+
}
22+
23+
// body = {
24+
// "inputMapping": { A dictionary where each key is a CSS selector, and each value is another dictionary containing details about the input for that element:
25+
// "selector": <string> The CSS selector for the input element (used as the key).
26+
// "value": <string> The text to be inputted into the element.
27+
// "delay": <number> A delay (in milliseconds) between each keystroke when inputting the text. Defaults to 0 if not provided.
28+
// },
29+
// "submitButton": <string> The CSS selector for the form's submit button. If provided, the button will be clicked after filling in the form.
30+
// }
31+
//
32+
router.post('/', async function (req, res, next) {
33+
34+
if (!req.body.inputMapping) {
35+
res.status(400);
36+
res.send("No inputMapping provided in fill_form request");
37+
next();
38+
return;
39+
}
40+
41+
try {
42+
let response = await utils.performAction(req, action);
43+
res.header('scrapy-puppeteer-service-context-id', response.contextId);
44+
res.send(response);
45+
} catch (e) {
46+
next(e);
47+
}
48+
});
49+
50+
module.exports = router;

0 commit comments

Comments
 (0)