如何使用axios在其他网站填写并提交表单?
How do I fill in and submit a form on another website with axios?
我正在用 Node.js 制作一个鞋子抽奖机器人,最初使用无头 Puppeteer 来自动完成抽奖表格的填写和提交过程。有人告诉我 Puppeteer 非常 CPU-intensive 并且比 Node.js 中的请求模块慢,例如 fetch、Axios 等
这两天一直在弄Axios,但是我真的不知道怎么填写和提交表单。我如何填写和提交我在 Axios 中描述的表格?此外,Axios 是否会成为最佳选择(就速度和 CPU 使用而言)还是有更好的选择?
Here is an example for a form I would like to fill in.
这是我填写表格的木偶代码:
const { sizeSelectorsTitolo } = require('./selectors/sizes');
const accounts = require('./profiles/savedaccounts');
const { proxyList1 } = require('./profiles/proxylists');
async function titoloMain(url, size, shippingprofile , ppaccountnumber, proxygroup, instaaccountnumber){
let splitProxy = proxygroup.split(':');
let proxyUserLocal = splitProxy[2];
let proxyPassLocal = splitProxy[3];
let proxyPortLocal = splitProxy[1];
let proxyMainLocal = splitProxy[0];
let countrySelector = '';
//Getting size selector ready
let OurSizeSelector = 'sizeSelectorsTitolo.'
OurSizeSelector = OurSizeSelector.concat(size);
delete OurSizeSelector.property;
OurSizeSelector = eval(OurSizeSelector);
//Getting country selector
switch (shippingprofile.country){
case shippingprofile.country = "UK":
countrySelector = 'United Kingdom'
break;
case shippingprofile.country = "USA":
countrySelector = 'United States of America'
break;
case shippingprofile.country = "France":
countrySelector = 'France'
break;
case shippingprofile.country = "Spain":
countrySelector = 'Spain'
break;
case shippingprofile.country = "Germany":
countrySelector = 'Germany'
break;
case shippingprofile.country = "Canada":
countrySelector = 'Canada'
break;
};
//getting gender selectors
let localGender = '';
if (shippingprofile.gender == 'Male'){
localGender = 'Male'
} else {
localGender = 'Female'
};
const browser = await puppetteer.launch( {
headless: true,
args: ['--disable-infobars',
`--window-size=${1000.},${1000.}`,
'--disable-features=IsolateOrigins,site-per-process',
//ip and port
`${proxyMainLocal}:${proxyPortLocal}`
],
ignoreDefaultArgs: ['--enable-automation']
});
const page = await browser.newPage();
//proxy settings
await page.authenticate({
username: proxyUserLocal,
password: proxyPassLocal
});
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36');
//now at the raffle page
console.log('on the raffle page')
await page.goto(url, {waitUntil:"networkidle2"});
console.log('filing out form...')
console.log('paypal')
await page.waitForSelector('#mce-EMAIL')
await page.type('#mce-EMAIL',accounts.paypalAccounts[ppaccountnumber].main,{delay:20})
console.log('name')
await page.type('#mce-FNAME',shippingprofile.firstname, {delay:20});
await page.type('#mce-LNAME',shippingprofile.surname, {delay:20});
console.log('shipping address')
await page.type('#mce-MMERGE5',shippingprofile.houseNum.concat(` ${shippingprofile.street}`), {delay:20});
await page.type('#mce-MMERGE8', shippingprofile.postcode , {delay:20});
await page.type('#mce-MMERGE12', shippingprofile.city , {delay:20});
await page.select('#mce-MMERGE3',countrySelector);
console.log('phone number')
await page.type('#mce-PHONE', shippingprofile.phoneNumber, {delay:20});
console.log('additional info')
await page.select('#mce-MMERGE9',localGender);
await page.select('#mce-MMERGE10','en');
console.log('instagram name')
await page.type('#mce-MMERGE7',accounts.instagram[instaaccountnumber].accountname,{delay:20});
console.log('selecting size')
await page.select('#mce-MMERGE6',OurSizeSelector)
console.log('clicking terms')
await page.waitForSelector('#mce-group\[199\]-199-0');
await page.waitFor(500);
await page.click('#mce-group\[199\]-199-0');
console.log('submitting')
await page.click('#mc-embedded-subscribe');
await page.waitFor(1000);
console.log(`done, check ${accounts.paypalAccounts[ppaccountnumber].main}`);
await browser.close()
};
这是 axios 的代码,我不知道如何将输入字段定位到 post 数据,所以我现在只记录 headers:
const axios = require('axios')
async function test() {
axios.get('https://en.titoloshop.com/titolo/air-jordan-1-retro-high-og-bio-hack/#raffle')
.then(res => {
console.log(res.headers)
})
.catch(err => {
if (err.response) {
console.log('there was an error');
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
}
});
}
TLDR: 使用适当的表单数据发出 POST
请求,并对表单的 action
元素进行适当的编码。可以通过查看表单的 input
或 select
元素的 name
属性找到要发送的键。向下滚动代码。
首先要知道Puppeteer and request modules such as axios and node-fetch的区别。 Puppeteer 用于控制浏览器并像用户使用网站一样使用网站,而 axios 用于简单地发出 HTTP 请求。因此,您无法执行单击按钮或填写表格等操作。
然而,提交表单通常只是简单地向另一个 URL 发出带有表单数据的 HTTP 请求。例如,这是抽奖表格的 HTML(简体):
<form
action="https://titolo.us6.list-manage.com/subscribe/post?u=652f80ec0adf2d7ac9588d0a1&id=8093f364b8"
method="post"
>
<div>
<label for="mce-EMAIL">Email Address* (PayPal)</label>
<input type="email" name="EMAIL" id="mce-EMAIL">
</div>
<!-- first name, last name, address, postcode, city -->
<div>
<label for="mce-MMERGE3">Country*</label>
<select name="MMERGE3" id="mce-MMERGE3">
<option value=""></option>
<option value="Switzerland">Switzerland</option>
<!-- more countries... -->
</select>
</div>
<!-- the rest of the inputs... -->
<div>
<strong>Terms & Conditions </strong>
<ul>
<li>
<input type="checkbox" name="group[243][1]" id="mce-group[243]-243-0">
<label for="mce-group[243]-243-0">I agree</label>
</li>
</ul>
</div>
<!-- more stuff... -->
<!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
<div style="position: absolute; left: -5000px">
<input
type="text"
name="b_652f80ec0adf2d7ac9588d0a1_8093f364b8"
tabindex="-1"
value=""
>
</div>
<div>
<input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe">
</div>
</form>
我们来分解一下。
<form action="..." method="post'>
:表单将POST
其在post正文中的数据传送到URL中指定的action
属性中。这将根据 enctype
属性进行编码。在这种情况下,它将是一个 application/x-www-form-urlencoded
字符串(例如 key1=value1&key2=value2
),这是默认值。
<input type="email" name="EMAIL" id="mce-EMAIL">
:输入的邮件将是post正文中EMAIL
键(由name
属性表示)的值。
<select name="MMERGE3" id="mce-MMERGE3">
:selected 选项将是 MMERGE3
键的值。
<option value="Switzerland">
每个选项都有一个 value
属性,它指定要在 post 正文中发送的字符串。这不需要与文本内容相同。如果不存在,将发送元素的文本内容。
<input type="checkbox" value="1" name="group[243][1]" id="mce-group[243]-243-0">
这是一个复选框输入。如果复选框是 selected,group[243][1]
(name
属性)将是 1
(value
属性,默认为 on
)在表单正文中。如果不 selected,group[243][1]
将不存在于正文中。
<input type="text" name="b_652f80ec0adf2d7ac9588d0a1_8093f364b8" tabindex="-1" value="">
根据评论,这是一个永远不应该填写的输入,只是为了防止机器人注册抽奖(讽刺是不是?)。
<input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe">
这是提交按钮。除非有 name
属性(就像任何其他 input
一样),否则不会提交此值,因此在这种情况下,将有一个名为 subscribe
的键,其值为 [=43] =](来自 value
属性)。默认 value
属性因浏览器而异:
<input type="submit">
有关提交表单如何工作的详细信息,请参阅 Sending form data on MDN。
因此,要在不使用 Puppeteer 的情况下提交此表单,您需要使用适当的 URL-encoded 表单值作为表单数据来发出 POST
请求。您可以像这样在 axios 中执行此操作 (documentation):
const url = 'https://titolo.us6.list-manage.com/subscribe/post?u=652f80ec0adf2d7ac9588d0a1&id=8093f364b8'
axios.post(url, new URLSearchParams({
EMAIL: accounts.paypalAccounts[ppaccountnumber].main,
FNAME: shippingprofile.firstname,
LNAME: shippingprofile.surname,
// Address
MMERGE5: shippingprofile.houseNum.concat(` ${shippingprofile.street}`),
// Postcode
MMERGE8: shippingprofile.postcode,
// City
MMERGE12: shippingprofile.city,
// Country
MMERGE3: countrySelector,
PHONE: shippingprofile.phoneNumber,
// Gender
MMERGE9: localGender,
// Language
MMERGE10: 'en',
// Size
MMERGE6: OurSizeSelector,
// Instagram account name
MMERGE7: accounts.instagram[instaaccountnumber].accountname,
// T&Cs
'group[243][1]': '1',
// That invisible input
b_652f80ec0adf2d7ac9588d0a1_8093f364b8: '',
// Subscribe button
subscribe: 'Subscribe'
}))
此代码应提交表单,就像用户在其网站上填写并提交表单一样。很可能并非所有这些都是实际需要的(例如订阅按钮和不可见输入),但我将它们包括在这里以防万一。
注意:该网站要求您 select 您希望从公司那里听到的方式:时事通讯 (name="gdpr[695]"
) and/or 抽奖信息 (name="gdpr[699]"
).这两个复选框都有 value="Y"
,所以如果您想将它们作为表单的一部分提交,只需将 'gdpr[695]': 'Y'
and/or 'gdpr[699]': 'Y'
添加到 URLSearchParams
构造函数。
我正在用 Node.js 制作一个鞋子抽奖机器人,最初使用无头 Puppeteer 来自动完成抽奖表格的填写和提交过程。有人告诉我 Puppeteer 非常 CPU-intensive 并且比 Node.js 中的请求模块慢,例如 fetch、Axios 等
这两天一直在弄Axios,但是我真的不知道怎么填写和提交表单。我如何填写和提交我在 Axios 中描述的表格?此外,Axios 是否会成为最佳选择(就速度和 CPU 使用而言)还是有更好的选择?
Here is an example for a form I would like to fill in.
这是我填写表格的木偶代码:
const { sizeSelectorsTitolo } = require('./selectors/sizes');
const accounts = require('./profiles/savedaccounts');
const { proxyList1 } = require('./profiles/proxylists');
async function titoloMain(url, size, shippingprofile , ppaccountnumber, proxygroup, instaaccountnumber){
let splitProxy = proxygroup.split(':');
let proxyUserLocal = splitProxy[2];
let proxyPassLocal = splitProxy[3];
let proxyPortLocal = splitProxy[1];
let proxyMainLocal = splitProxy[0];
let countrySelector = '';
//Getting size selector ready
let OurSizeSelector = 'sizeSelectorsTitolo.'
OurSizeSelector = OurSizeSelector.concat(size);
delete OurSizeSelector.property;
OurSizeSelector = eval(OurSizeSelector);
//Getting country selector
switch (shippingprofile.country){
case shippingprofile.country = "UK":
countrySelector = 'United Kingdom'
break;
case shippingprofile.country = "USA":
countrySelector = 'United States of America'
break;
case shippingprofile.country = "France":
countrySelector = 'France'
break;
case shippingprofile.country = "Spain":
countrySelector = 'Spain'
break;
case shippingprofile.country = "Germany":
countrySelector = 'Germany'
break;
case shippingprofile.country = "Canada":
countrySelector = 'Canada'
break;
};
//getting gender selectors
let localGender = '';
if (shippingprofile.gender == 'Male'){
localGender = 'Male'
} else {
localGender = 'Female'
};
const browser = await puppetteer.launch( {
headless: true,
args: ['--disable-infobars',
`--window-size=${1000.},${1000.}`,
'--disable-features=IsolateOrigins,site-per-process',
//ip and port
`${proxyMainLocal}:${proxyPortLocal}`
],
ignoreDefaultArgs: ['--enable-automation']
});
const page = await browser.newPage();
//proxy settings
await page.authenticate({
username: proxyUserLocal,
password: proxyPassLocal
});
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36');
//now at the raffle page
console.log('on the raffle page')
await page.goto(url, {waitUntil:"networkidle2"});
console.log('filing out form...')
console.log('paypal')
await page.waitForSelector('#mce-EMAIL')
await page.type('#mce-EMAIL',accounts.paypalAccounts[ppaccountnumber].main,{delay:20})
console.log('name')
await page.type('#mce-FNAME',shippingprofile.firstname, {delay:20});
await page.type('#mce-LNAME',shippingprofile.surname, {delay:20});
console.log('shipping address')
await page.type('#mce-MMERGE5',shippingprofile.houseNum.concat(` ${shippingprofile.street}`), {delay:20});
await page.type('#mce-MMERGE8', shippingprofile.postcode , {delay:20});
await page.type('#mce-MMERGE12', shippingprofile.city , {delay:20});
await page.select('#mce-MMERGE3',countrySelector);
console.log('phone number')
await page.type('#mce-PHONE', shippingprofile.phoneNumber, {delay:20});
console.log('additional info')
await page.select('#mce-MMERGE9',localGender);
await page.select('#mce-MMERGE10','en');
console.log('instagram name')
await page.type('#mce-MMERGE7',accounts.instagram[instaaccountnumber].accountname,{delay:20});
console.log('selecting size')
await page.select('#mce-MMERGE6',OurSizeSelector)
console.log('clicking terms')
await page.waitForSelector('#mce-group\[199\]-199-0');
await page.waitFor(500);
await page.click('#mce-group\[199\]-199-0');
console.log('submitting')
await page.click('#mc-embedded-subscribe');
await page.waitFor(1000);
console.log(`done, check ${accounts.paypalAccounts[ppaccountnumber].main}`);
await browser.close()
};
这是 axios 的代码,我不知道如何将输入字段定位到 post 数据,所以我现在只记录 headers:
const axios = require('axios')
async function test() {
axios.get('https://en.titoloshop.com/titolo/air-jordan-1-retro-high-og-bio-hack/#raffle')
.then(res => {
console.log(res.headers)
})
.catch(err => {
if (err.response) {
console.log('there was an error');
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
}
});
}
TLDR: 使用适当的表单数据发出 POST
请求,并对表单的 action
元素进行适当的编码。可以通过查看表单的 input
或 select
元素的 name
属性找到要发送的键。向下滚动代码。
首先要知道Puppeteer and request modules such as axios and node-fetch的区别。 Puppeteer 用于控制浏览器并像用户使用网站一样使用网站,而 axios 用于简单地发出 HTTP 请求。因此,您无法执行单击按钮或填写表格等操作。
然而,提交表单通常只是简单地向另一个 URL 发出带有表单数据的 HTTP 请求。例如,这是抽奖表格的 HTML(简体):
<form
action="https://titolo.us6.list-manage.com/subscribe/post?u=652f80ec0adf2d7ac9588d0a1&id=8093f364b8"
method="post"
>
<div>
<label for="mce-EMAIL">Email Address* (PayPal)</label>
<input type="email" name="EMAIL" id="mce-EMAIL">
</div>
<!-- first name, last name, address, postcode, city -->
<div>
<label for="mce-MMERGE3">Country*</label>
<select name="MMERGE3" id="mce-MMERGE3">
<option value=""></option>
<option value="Switzerland">Switzerland</option>
<!-- more countries... -->
</select>
</div>
<!-- the rest of the inputs... -->
<div>
<strong>Terms & Conditions </strong>
<ul>
<li>
<input type="checkbox" name="group[243][1]" id="mce-group[243]-243-0">
<label for="mce-group[243]-243-0">I agree</label>
</li>
</ul>
</div>
<!-- more stuff... -->
<!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
<div style="position: absolute; left: -5000px">
<input
type="text"
name="b_652f80ec0adf2d7ac9588d0a1_8093f364b8"
tabindex="-1"
value=""
>
</div>
<div>
<input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe">
</div>
</form>
我们来分解一下。
<form action="..." method="post'>
:表单将POST
其在post正文中的数据传送到URL中指定的action
属性中。这将根据enctype
属性进行编码。在这种情况下,它将是一个application/x-www-form-urlencoded
字符串(例如key1=value1&key2=value2
),这是默认值。<input type="email" name="EMAIL" id="mce-EMAIL">
:输入的邮件将是post正文中EMAIL
键(由name
属性表示)的值。<select name="MMERGE3" id="mce-MMERGE3">
:selected 选项将是MMERGE3
键的值。<option value="Switzerland">
每个选项都有一个value
属性,它指定要在 post 正文中发送的字符串。这不需要与文本内容相同。如果不存在,将发送元素的文本内容。
<input type="checkbox" value="1" name="group[243][1]" id="mce-group[243]-243-0">
这是一个复选框输入。如果复选框是 selected,group[243][1]
(name
属性)将是1
(value
属性,默认为on
)在表单正文中。如果不 selected,group[243][1]
将不存在于正文中。<input type="text" name="b_652f80ec0adf2d7ac9588d0a1_8093f364b8" tabindex="-1" value="">
根据评论,这是一个永远不应该填写的输入,只是为了防止机器人注册抽奖(讽刺是不是?)。<input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe">
这是提交按钮。除非有name
属性(就像任何其他input
一样),否则不会提交此值,因此在这种情况下,将有一个名为subscribe
的键,其值为 [=43] =](来自value
属性)。默认value
属性因浏览器而异:<input type="submit">
有关提交表单如何工作的详细信息,请参阅 Sending form data on MDN。
因此,要在不使用 Puppeteer 的情况下提交此表单,您需要使用适当的 URL-encoded 表单值作为表单数据来发出 POST
请求。您可以像这样在 axios 中执行此操作 (documentation):
const url = 'https://titolo.us6.list-manage.com/subscribe/post?u=652f80ec0adf2d7ac9588d0a1&id=8093f364b8'
axios.post(url, new URLSearchParams({
EMAIL: accounts.paypalAccounts[ppaccountnumber].main,
FNAME: shippingprofile.firstname,
LNAME: shippingprofile.surname,
// Address
MMERGE5: shippingprofile.houseNum.concat(` ${shippingprofile.street}`),
// Postcode
MMERGE8: shippingprofile.postcode,
// City
MMERGE12: shippingprofile.city,
// Country
MMERGE3: countrySelector,
PHONE: shippingprofile.phoneNumber,
// Gender
MMERGE9: localGender,
// Language
MMERGE10: 'en',
// Size
MMERGE6: OurSizeSelector,
// Instagram account name
MMERGE7: accounts.instagram[instaaccountnumber].accountname,
// T&Cs
'group[243][1]': '1',
// That invisible input
b_652f80ec0adf2d7ac9588d0a1_8093f364b8: '',
// Subscribe button
subscribe: 'Subscribe'
}))
此代码应提交表单,就像用户在其网站上填写并提交表单一样。很可能并非所有这些都是实际需要的(例如订阅按钮和不可见输入),但我将它们包括在这里以防万一。
注意:该网站要求您 select 您希望从公司那里听到的方式:时事通讯 (name="gdpr[695]"
) and/or 抽奖信息 (name="gdpr[699]"
).这两个复选框都有 value="Y"
,所以如果您想将它们作为表单的一部分提交,只需将 'gdpr[695]': 'Y'
and/or 'gdpr[699]': 'Y'
添加到 URLSearchParams
构造函数。