使用 PhantomJS 处理多个用户对多个远程 Web 表单的请求
Handle multiple users requests to multiple remote web forms using PhantomJS
我使用 NightmareJS 创建了一个 ExpressJS 应用程序,它有一个表单,当我们填写表单并提交时,它会向一些远程表单发送请求并计算数据和 return 这些结果。但问题是它只在单个客户提交表单时有效。当多个客户同时提交表单时,它不起作用。这可能是什么原因以及如何解决这个问题?
前端JS脚本
$(document).ready(function () {
$("#calculate-form").submit(function (event) {
var request;
if (request) {
request.abort();
}
var $form = $(this);
var $inputs = $form.find("input, select, button, textarea");
var serializedData = $form.serialize();
$inputs.prop("disabled", true);
form1(request, serializedData, $inputs, '/example1', '#form1');
function form1(request, serializedData, inputs, appUrl, displayElement)
{
request = $.ajax({
url: appUrl,
type: "post",
data: serializedData
});
request.done(function (response) {
$(displayElement).text(response.value);
form2(request, serializedData, $inputs, '/example2', '#form2');
function form2(request, serializedData, inputs, appUrl, displayElement)
{
request = $.ajax({
url: appUrl,
type: "post",
data: serializedData
});
request.done(function (response) {
$(displayElement).text(response.value);
});
request.fail(function (jqXHR, textStatus, errorThrown) {
console.log("Failed");
});
}
});
request.fail(function (jqXHR, textStatus, errorThrown) {
console.log("Failed");
});
}
event.preventDefault();
});
});
ExpressJS 索引脚本
var express = require('express');
var app = express();
var phantom = require('phantom');
var bodyParser = require('body-parser');
var Nightmare = require('nightmare');
app.use(bodyParser.urlencoded({
extended: true
}));
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/'));
app.engine('html', require('ejs').renderFile);
app.get('/', function (request, response) {
response.render('index.html');
});
app.listen(app.get('port'), function () {
console.log('Scrapper is running on port', app.get('port'));
});
require('./form1')(app, Nightmare);
require('./form2')(app, Nightmare);
ExpressJS form1 脚本
module.exports = function (app, Nightmare) {
var nightmare1 = Nightmare({
show: true
});
app.post('/example1', function (req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Content-Type', 'application/json');
try
{
if (req.method === 'POST') {
var requestParams = req.body;
nightmare1
.goto('https://example1.com/form')
.evaluate(function () {
var select = document.querySelector('#RepaymentMethod');
select.value = "1";
select.dispatchEvent(new Event('change'));
})
.wait("#formbtn-1")
.evaluate(function () {
document.getElementById('inputfield_1').value = "inputfield-1-Value";
document.getElementById('btnSubmitform').click();
})
.wait("#resultvalue")
.evaluate(function () {
var str = document.querySelector('#resultvalue').innerText;
return res;
})
.end()
.then(function (form1) {
res.send({value: form1});
nightmare1.halt();
})
.catch(function (error) {
res.send({'error': error});
nightmare1.halt();
});
}
} catch (err)
{
res.sendStatus(400).send(err);
nightmare1.halt();
process.exit();
}
});
}
ExpressJS form2 脚本
module.exports = function (app, Nightmare) {
var nightmare2 = Nightmare({
show: true
});
app.post('/example2', function (req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Content-Type', 'application/json');
try
{
if (req.method === 'POST') {
var requestParams = req.body;
nightmare2
.goto('https://example2.com/form')
.evaluate(function () {
var select = document.querySelector('#RepaymentMethod');
select.value = "10";
select.dispatchEvent(new Event('change'));
})
.wait("#formbtn-1")
.evaluate(function () {
document.getElementById('inputfield_1').value = "inputfield-1-Value";
document.getElementById('inputfield_2').value = "inputfield-2-Value";
document.getElementById('btnSubmitform').click();
})
.wait("#resultvalue")
.evaluate(function () {
var str = document.querySelector('#resultvalue').innerText;
return res;
})
.end()
.then(function (form2) {
res.send({value: form2});
nightmare2.halt();
process.exit();
})
.catch(function (error) {
res.send({'error': error});
nightmare2.halt();
process.exit();
});
}
} catch (err)
{
res.sendStatus(400).send(err);
nightmare2.halt();
process.exit();
}
});
}
根据您发布的示例,您正尝试在多个请求中重复使用同一个 Nightmare 实例。这不会像您有多个请求一样工作,稍后请求的操作将添加到当前正在执行的上下文中。这更加复杂,因为您还 .end()
访问实例,导致 Nightmare 实例在初始请求后无法使用。
如果将 Nightmare 实例化移动到 Express post
方法中,您的运气可能会更好,但要小心:此方法的扩展性不是特别好。
我使用 NightmareJS 创建了一个 ExpressJS 应用程序,它有一个表单,当我们填写表单并提交时,它会向一些远程表单发送请求并计算数据和 return 这些结果。但问题是它只在单个客户提交表单时有效。当多个客户同时提交表单时,它不起作用。这可能是什么原因以及如何解决这个问题?
前端JS脚本
$(document).ready(function () {
$("#calculate-form").submit(function (event) {
var request;
if (request) {
request.abort();
}
var $form = $(this);
var $inputs = $form.find("input, select, button, textarea");
var serializedData = $form.serialize();
$inputs.prop("disabled", true);
form1(request, serializedData, $inputs, '/example1', '#form1');
function form1(request, serializedData, inputs, appUrl, displayElement)
{
request = $.ajax({
url: appUrl,
type: "post",
data: serializedData
});
request.done(function (response) {
$(displayElement).text(response.value);
form2(request, serializedData, $inputs, '/example2', '#form2');
function form2(request, serializedData, inputs, appUrl, displayElement)
{
request = $.ajax({
url: appUrl,
type: "post",
data: serializedData
});
request.done(function (response) {
$(displayElement).text(response.value);
});
request.fail(function (jqXHR, textStatus, errorThrown) {
console.log("Failed");
});
}
});
request.fail(function (jqXHR, textStatus, errorThrown) {
console.log("Failed");
});
}
event.preventDefault();
});
});
ExpressJS 索引脚本
var express = require('express');
var app = express();
var phantom = require('phantom');
var bodyParser = require('body-parser');
var Nightmare = require('nightmare');
app.use(bodyParser.urlencoded({
extended: true
}));
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/'));
app.engine('html', require('ejs').renderFile);
app.get('/', function (request, response) {
response.render('index.html');
});
app.listen(app.get('port'), function () {
console.log('Scrapper is running on port', app.get('port'));
});
require('./form1')(app, Nightmare);
require('./form2')(app, Nightmare);
ExpressJS form1 脚本
module.exports = function (app, Nightmare) {
var nightmare1 = Nightmare({
show: true
});
app.post('/example1', function (req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Content-Type', 'application/json');
try
{
if (req.method === 'POST') {
var requestParams = req.body;
nightmare1
.goto('https://example1.com/form')
.evaluate(function () {
var select = document.querySelector('#RepaymentMethod');
select.value = "1";
select.dispatchEvent(new Event('change'));
})
.wait("#formbtn-1")
.evaluate(function () {
document.getElementById('inputfield_1').value = "inputfield-1-Value";
document.getElementById('btnSubmitform').click();
})
.wait("#resultvalue")
.evaluate(function () {
var str = document.querySelector('#resultvalue').innerText;
return res;
})
.end()
.then(function (form1) {
res.send({value: form1});
nightmare1.halt();
})
.catch(function (error) {
res.send({'error': error});
nightmare1.halt();
});
}
} catch (err)
{
res.sendStatus(400).send(err);
nightmare1.halt();
process.exit();
}
});
}
ExpressJS form2 脚本
module.exports = function (app, Nightmare) {
var nightmare2 = Nightmare({
show: true
});
app.post('/example2', function (req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Content-Type', 'application/json');
try
{
if (req.method === 'POST') {
var requestParams = req.body;
nightmare2
.goto('https://example2.com/form')
.evaluate(function () {
var select = document.querySelector('#RepaymentMethod');
select.value = "10";
select.dispatchEvent(new Event('change'));
})
.wait("#formbtn-1")
.evaluate(function () {
document.getElementById('inputfield_1').value = "inputfield-1-Value";
document.getElementById('inputfield_2').value = "inputfield-2-Value";
document.getElementById('btnSubmitform').click();
})
.wait("#resultvalue")
.evaluate(function () {
var str = document.querySelector('#resultvalue').innerText;
return res;
})
.end()
.then(function (form2) {
res.send({value: form2});
nightmare2.halt();
process.exit();
})
.catch(function (error) {
res.send({'error': error});
nightmare2.halt();
process.exit();
});
}
} catch (err)
{
res.sendStatus(400).send(err);
nightmare2.halt();
process.exit();
}
});
}
根据您发布的示例,您正尝试在多个请求中重复使用同一个 Nightmare 实例。这不会像您有多个请求一样工作,稍后请求的操作将添加到当前正在执行的上下文中。这更加复杂,因为您还 .end()
访问实例,导致 Nightmare 实例在初始请求后无法使用。
如果将 Nightmare 实例化移动到 Express post
方法中,您的运气可能会更好,但要小心:此方法的扩展性不是特别好。