在给 ChatGPT 代充 Plus 会员时,每次电脑上都是填入同样的信息,比如信用卡和地址。这个过程大概就是重复:复制链接 – 打开浏览器 – 填入信用卡 – 填入账单地址 – 点提交。我想着应该可以用 Puppeteer实现自动化操作,又因为 ChatGPT 升级 Plus 采用 Stripe 网关付款,它们做了非常严格的反爬措施,所以这里再用 Stealth 模拟更真实的浏览器行为。
下面是我的代码,因为我后面不需要这个自动化,所以没完全测试,但大致是没问题的,可以参考一二。
首先创建一个账单地址 address.js
,这里我采用韩国的地区和市,我希望每次进入页面随机抽取其中一个填入,所以这是一个数组。
const addresses = [
{
area: '대구광역시',
billingLocality: 'Daegu',
billingDependentLocality: 'Daegu',
addressLine1: '82-2, Sangyeog 2(i)-dong, Buk-gu, Daegu',
billingPostalCode: '702-012'
},
{
area: '충청북도',
billingLocality: 'Incheon',
billingDependentLocality: 'Incheon',
addressLine1: '72-2, Hwasanri, Chopyeong-myeon, Jincheon-gun, Chungcheongbuk-do',
billingPostalCode: '365-851'
},
{
area: '대구광역시',
billingLocality: 'Daegu',
billingDependentLocality: 'Daegu',
addressLine1: '1500-7, Sangyeog 4(sa)-dong, Buk-gu, Daegu',
billingPostalCode: '702-843'
},
{
area: '전라북도',
billingLocality: 'Jeonju',
billingDependentLocality: 'Jeonju',
addressLine1: '367-10, Jungnosong-dong, Wansan-gu Jeonju-si, Jeollabuk-do',
billingPostalCode: '560-861'
}
];
module.exports = addresses;
接着创建主程序文件 chatgpt-plus-pag.js
,因为我希望一张信用卡付款失败,再次填入其他信用卡。现在主文件中添加信用卡信息
const infoList = [
{
cardNumber: '5205143438492643',
cardExpiry: '0326',
cardCvc: '817',
billingName: 'Stacey Smith'
}
,
{
cardNumber: '5205143802556866',
cardExpiry: '0326',
cardCvc: '759',
billingName: 'Stacey Williams'
},
];
安装 Puppeteer 拓展插件,才能引入使用
npm install puppeteer-extra puppeteer-extra-plugin-stealth
在主程序添加引入代码
const puppeteer = require('puppeteer-extra');
const addresses = require('./address.js');
const fs = require('fs');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin({
screenResolution: '1680x1050', // 设置屏幕分辨率
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36', // 设置用户代理为 Macbook Pro
locale: 'en-US', // 设置语言区域
}));
我希望每次点击执行后,在本地将使用的信用卡信息和充值邮箱、时间写入到本地,当做记录,每次执行追加记录一条。
async function saveDataToFile(page) {
// 获取邮箱和卡号
const email = await page.$eval('.ReadOnlyFormField-title', el => el.innerText);
const cardNumber = await page.$eval('#cardNumber', el => el.value);
// 获取当前日期时间
const dateTime = new Date().toLocaleString();
// 将数据写入文件
fs.appendFileSync('data.txt', `${dateTime}\nEmail: ${email}\nCard Number: ${cardNumber}\n\n`);
}
还有个特殊的地方,默认加载页面这个地址可能显示全部,也可能要手动展开。
所以我们需要判断,如果存在手动输入地址的按钮,则点击按钮并等待表单出现后手动填写地址。
OK,这里我贴出主程序完整代码。
const puppeteer = require('puppeteer-extra');
const addresses = require('./address.js');
const fs = require('fs');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin({
screenResolution: '1680x1050', // 设置屏幕分辨率
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36', // 设置用户代理为 Macbook Pro
locale: 'en-US', // 设置语言区域
}));
(async () => {
// 启动 Puppeteer
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
args: [
'--start-maximized',
'--disable-cache',
'--disable-application-cache'
],
userDataDir: '/tmp/puppeteer_user_data'
});
// 创建一个新页面
const page = await browser.newPage();
// 访问网站
// 读取文件内容(本地创建 url.txt )
const url = fs.readFileSync('./url.txt', 'utf-8');
await page.goto(url);
for (let i = 0; i < infoList.length; i++) {
const info = infoList[i];
// 填写表单
await page.waitForSelector('input[name="cardNumber"]', { timeout: 5000, visible: true });
await page.type('input[name="cardNumber"]', info.cardNumber,{delay: 100});
await page.type('input[name="cardExpiry"]', info.cardExpiry,{delay: 100});
await page.type('input[name="cardCvc"]', info.cardCvc,{delay: 100});
await page.type('input[name="billingName"]', info.billingName,{delay: 100});
// 判断是否需要输入账单地址
const addressButton = await page.$('.Text.Text-color--gray400.Text-fontSize--12.Text-fontWeight--400');
//获取随机地址
const randomIndex = Math.floor(Math.random() * addresses.length);
const address = addresses[randomIndex];
if (addressButton) {
// 如果存在手动输入地址的按钮,则点击按钮并等待表单出现后手动填写地址
await addressButton.click();
await page.waitForSelector('input[name="billingPostalCode"]');
await fillAddress(page,address);
} else {
// 如果不存在手动输入地址的按钮,则直接填写地址
await fillAddress(page,address);
}
await page.waitForTimeout(1000); // 添加延迟
await page.waitForSelector('#termsOfServiceConsentCheckbox'); // 等待单选框加载
await page.evaluate(() => {
document.querySelector('#termsOfServiceConsentCheckbox').click(); // 模拟单击事件
});
//写入数据到本地
saveDataToFile(page);
// 提交表单
await page.waitForSelector('button[type="submit"]:not([disabled])');
await page.click('button[type="submit"]');
}
// 关闭浏览器
// await browser.close();
})();
async function fillAddress(page,address) {
const {area, billingLocality, billingDependentLocality, addressLine1, billingPostalCode} = address;
await page.select('#billingAdministrativeArea', area);
await page.waitForTimeout(1000); // 添加延迟
await page.focus('input[name="billingLocality"]');
await page.type('input[name="billingLocality"]', billingLocality);
await page.waitForTimeout(500); // 添加延迟
await page.type('input[name="billingDependentLocality"]', billingDependentLocality);
await page.waitForTimeout(500); // 添加延迟
await page.type('input[name="billingAddressLine1"]', addressLine1 ,{delay: 100});
await page.waitForTimeout(500); // 添加延迟
await page.type('input[name="billingPostalCode"]', billingPostalCode ,{delay: 100});
}
async function saveDataToFile(page) {
// 获取邮箱和卡号
const email = await page.$eval('.ReadOnlyFormField-title', el => el.innerText);
const cardNumber = await page.$eval('#cardNumber', el => el.value);
// 获取当前日期时间
const dateTime = new Date().toLocaleString();
// 将数据写入文件
fs.appendFileSync('data.txt', `${dateTime}\nEmail: ${email}\nCard Number: ${cardNumber}\n\n`);
}
const infoList = [
{
cardNumber: '5405243438492643',
cardExpiry: '0326',
cardCvc: '847',
billingName: 'Stacey Smith'
}
,
{
cardNumber: '5405243802556866',
cardExpiry: '0326',
cardCvc: '759',
billingName: 'Stacey Williams'
},
];
OK,希望这个浏览器自动付款脚本对你有用。
本文由老郭种树原创,转载请注明:https://guozh.net/puppeter-simulates-browser-automatic-payment/