泥潭日报 uscardforum · 每日精选

【半自动轮椅♿️】分享一个AA搜JL票脚本,我太太太奶奶都会用

内容摘要

半自动AA搜票脚本绕过风控的核心操作与限制。

1. 关键信息

  • 需从Chrome Console运行JavaScript代码,依赖当前Session的Cookie与credentials。
  • 禁403/400主要因请求过快或浏览器profile重复,建议500ms-3s延迟。
  • 一次扫描强制整月(calendar API限制),每日日期可改但易触发风控。
  • 被封后换浏览器profile或IP可解,通常约一天(#1, #11, #14, #16, #45, #50, #55)。
  • 进阶方案:ip pool + 自动化浏览器 + Telegram/Discord通知 + 改用Python/Selenium(#53, #55, #56)。

2. 羊毛/优惠信息

无。

3. 最新动态

  • 作者已提供免Code的Bookmarklet/GreaseMonkey插件,简化至点击安装运行(#32)。

4. 争议或不同意见

  • 有人质疑全自动在Akamai下极易触发Challenge,shell/python难绕过,必须用自动化浏览器(#24, #55, #56)。
  • 有人反映即使控制间隔仍被ban,怀疑与profile或Akamai算法有关(#11, #16, #50)。

5. 行动建议

  • 小白使用提供的Bookmarklet;进阶用户可叠加ip pool与自动化浏览器。
  • 扫描时控制请求间隔,优先在非高峰时段操作,避免频繁触发风控。
原始内容
--- 第 1 楼来自 AnonAno 的回复 (2026-01-02 06:04:23 PST) ---

去年AA大幅增强风控,导致之前大佬分享的全自动脚本不再能用,会一直报错说access blocked。
【引用自 未知】:
【真】全自动AA搜票工具,我太奶奶都会用 航空常旅客
拜读过 0基础用Python和Postman搜里程票教程 - 旅行 / 航空常旅客 - 美卡论坛 之后,深受启发,但与此同时感到虽然 @smb 大佬已经尽量嚼碎了喂饭给大家,这里还是有些技术门槛在的。为此,我将其包装起来,供大家更方便使用。
需求
google 账号
浏览器(手机/电脑/anywhere)
使用步骤
点开 Google Colab
[image]
右上角登录Go…
基于这个稍微改了几个版本,这里分享个半自动,但也是用起来最最方便的轮椅,至少大家能自己动手丰衣足食

原理其实很简单,现在搜票api不能单独发了,需要cookie和credentials,我们直接从chrome里偷来发api reqest。
注意事项

还是不能发太多request,暂时没试出来准确limit,同ip发多了会被封ip+brower,换个brower能破。被封的过段时间也会自己解开,具体时间不记得了,好像是一天?

这个需要手动自己每次跑,跑的时候重新execute。也可以改成loop,但是cookie可能会过期,而且被封的概率大幅增加

使用步骤

打开 aa.com

F12打开console,第一次execute command 需要手动允许一下

复制这段代码跑就行了,记得改下参数, 在最上面几行,比较self explanatory。 主要就是改你的起飞机场和日期

// === AA Award Calendar Scanner - Run in browser console on aa.com ===

(async function() {
// ================== CONFIGURATION ==================
const fromYear = 2026;
const fromMonth = 2; // January = 1
const toMonth = 1; //
const origins = ['JFK', 'TYO'];
const destinations = ['TYO', 'JFK'];
const cabin = 'BUSINESS,FIRST'; // Options: "COACH", "PREMIUM_COACH", "BUSINESS,FIRST"
const maxStops = '1'; // "0", "1", "2"
const includeLink = true;
const delayMs = 300; // Delay between requests (ms) - do not set to 0
// ===================================================

const TYO = new Set(['NRT', 'HND']);

function isSameCity(a, b) {
return a === b || (TYO.has(a) && TYO.has(b));
}

// Build list of dates to query (first day of each month)
const dates = [];
for (let year = fromYear; year <= (fromMonth <= toMonth ? fromYear : fromYear + 1); year++) {
const startM = year === fromYear ? fromMonth : 1;
const endM = year === fromYear && fromMonth <= toMonth ? toMonth : (year > fromYear ? toMonth : 12);
for (let month = startM; month <= endM; month++) {
dates.push(`${year}-${String(month).padStart(2, '0')}-01`);
}
}

console.log(`Starting scan: ${dates.length} months × ${origins.length} origins × ${destinations.length} destinations / 2 (roundtrip) = ${dates.length * origins.length * destinations.length/2} total requests`);

const results = [];
let totalRequests = 0;

for (const depDate of dates) {
for (const origin of origins) {
for (const dest of destinations) {
if (isSameCity(origin, dest)) continue;

totalRequests++;
await new Promise(r => setTimeout(r, delayMs));

let foundInThisMonth = 0;

try {
const response = await fetch("https://www.aa.com/booking/api/search/calendar", {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "en-US",
"content-type": "application/json",
"cache-control": "no-cache",
"pragma": "no-cache",
"priority": "u=1, i",
"sec-ch-ua": "\"Chromium\";v=\"142\", \"Google Chrome\";v=\"142\", \"Not_A Brand\";v=\"99\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"macOS\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin"
},
"referrer": "https://www.aa.com/booking/choose-flights",
"body": JSON.stringify({
"metadata": { "selectedProducts": [], "tripType": "OneWay", "udo": {} },
"passengers": [{ "type": "adult", "count": 1 }],
"requestHeader": { "clientId": "AAcom" },
"slices": [{
"allCarriers": true,
"cabin": cabin,
"departureDate": depDate,
"destination": dest,
"destinationNearbyAirports": false,
"maxStops": maxStops,
"origin": origin,
"originNearbyAirports": false
}],
"tripOptions": {
"corporateBooking": false,
"fareType": "Lowest",
"locale": "en_US",
"pointOfSale": null,
"searchType": "Award"
},
"loyaltyInfo": null,
"version": "",
"queryParams": { "sliceIndex": 0, "sessionId": "", "solutionSet": "", "solutionId": "" }
}),
"method": "POST",
"mode": "cors",
"credentials": "include"
});

if (!response.ok) {
console.log(`⚠️ ${depDate} ${origin}→${dest}: HTTP ${response.status} (skipped)`);
continue;
}

const data = await response.json();

for (const month of data.calendarMonths || []) {
for (const week of month.weeks || []) {
for (const day of week.days || []) {
if (!day.validDay) continue;
const solution = day.solution;
if (solution && solution.perPassengerAwardPoints < 100000) {
foundInThisMonth++;
const bookUrl = `https://www.aa.com/booking/search?type=OneWay&searchType=Award&from=${origin}&to=${dest}&pax=1&cabin=${cabin}&locale=en_US&nearbyAirports=false&depart=${day.date}&carriers=ALL&pos=US&adult=1`;

// Detailed find with full link
console.log(`🎯 Found: ${day.date} (${new Date(day.date).toLocaleDateString('en-US', { weekday: 'short' })}) ${origin}→${dest} | ${solution.perPassengerAwardPoints.toLocaleString()} points + $${solution.perPassengerSaleTotal?.amount || 0} | ${bookUrl}`);

results.push({
date: day.date,
route: `${origin} → ${dest}`,
dayOfWeek: new Date(day.date).toLocaleDateString('en-US', { weekday: 'short' }),
points: solution.perPassengerAwardPoints.toLocaleString(),
cash: solution.perPassengerSaleTotal?.amount || 0,
currency: solution.perPassengerSaleTotal?.currency || 'USD',
link: includeLink ? `<a href="${bookUrl}" target="_blank">Book</a>` : ''
});
}
}
}
}

} catch (err) {
console.log(`💥 Error on ${depDate} ${origin}→${dest}: ${err.message}`);
}

// === PROGRESS UPDATE FOR THIS MONTH/ROUTE ===
if (foundInThisMonth > 0) {
console.log(`✅ ${depDate} ${origin}→${dest}: Found ${foundInThisMonth} award dates`);
} else {
console.log(`❌ ${depDate} ${origin}→${dest}: No availability`);
}
}
}
}

// ============= DISPLAY FINAL RESULTS =============
console.log(`\nScan complete! Processed ${totalRequests} requests.`);

if (results.length === 0) {
document.body.insertAdjacentHTML('beforeend', '<h2 style="color:orange">No award availability found in the scanned period 😔</h2>');
return;
}

results.sort((a, b) => a.date.localeCompare(b.date));

let tableHTML = `
<h2 style="color:green">🎉 Found ${results.length} Award Opportunities!</h2>
<p><strong>Scanned period:</strong> ${dates[0]} to ${dates[dates.length-1].slice(0,7)}-31</p>
<table border="1" cellpadding="8" cellspacing="0" style="border-collapse:collapse; font-family:Arial; background:white; margin-top:20px;">
<thead style="background:#f0f0f0">
<tr>
<th>Date</th>
<th>Day</th>
<th>Route</th>
<th>Points</th>
<th>+ Cash</th>
<th>Link</th>
</tr>
</thead>
<tbody>`;

for (const r of results) {
tableHTML += `
<tr>
<td>${r.date}</td>
<td>${r.dayOfWeek}</td>
<td>${r.route}</td>
<td style="text-align:right; font-weight:bold">${r.points}</td>
<td style="text-align:right">${r.cash} ${r.currency}</td>
<td>${r.link}</td>
</tr>`;
}

tableHTML += `</tbody></table>`;

document.body.insertAdjacentHTML('afterbegin', tableHTML);

console.log(`${results.length} total awards displayed in table above.`);
})();

效果演示

Screenshot 2026-01-02 at 5.55.55 AM1920×1013 403 KB
希望大家新年都能找到属于自己的票!

--- 第 3 楼来自 YamaFuso 的回复 (2026-01-02 08:03:36 PST) ---

【引用自 AnonAno】:
ip+brower
捉个虫 感觉应该是browser(?)

--- 第 4 楼来自 AnonAno 的回复 (2026-01-02 08:05:52 PST) ---

大半夜写的有点神智不清 感谢错字侠出警

--- 第 5 楼来自 Guardian_Ryan 的回复 (2026-01-02 08:12:29 PST) ---

牛的兄弟

--- 第 6 楼来自 MewTwo 的回复 (2026-01-02 08:48:55 PST) ---

感谢!找AI改成了bookmarklet,放在书签栏点击运行。

--- 第 7 楼来自 AnonAno 的回复 (2026-01-02 08:52:23 PST) ---

强! 我今天点赞到上限了…

不介意的话可以分享下,我link进主楼

估计还有很多能优化的地方 晚点我再改改!

--- 第 8 楼来自 gin_m 的回复 (2026-01-02 08:55:06 PST) ---

昨晚我太太太奶奶托梦让我烧一台好点的电脑下去。

--- 第 9 楼来自 Corsair 的回复 (2026-01-02 08:55:59 PST) ---

竟然还有上限!从来没到过,上限是多少?

--- 第 10 楼来自 hitmonlee 的回复 (2026-01-02 08:59:08 PST) ---

y/m/d里的day是不是还要改一下 现在貌似hard code成只搜每个月1号?

--- 第 11 楼来自 AnonAno 的回复 (2026-01-02 08:59:32 PST) ---

hmm 我发的这个版本脚本loop可能没问题,但也不推荐,因为我自己也被block过

我还有一版是会去qurey individual flight 去看机型,那个很容易死。两圈下来可能也就200个request 5min,大概跑十几分钟就无了。不知道是不是我哪里写的有问题。

他们用的好像是akami有点随机 我一直找不到规律

--- 第 12 楼来自 Corsair 的回复 (2026-01-02 09:03:17 PST) ---

我其实问的是点赞上限

--- 第 13 楼来自 AnonAno 的回复 (2026-01-02 09:11:34 PST) ---

哦哦 你说点赞吗(

我是50 可能我等级太菜了

--- 第 14 楼来自 Corsair 的回复 (2026-01-02 09:15:20 PST) ---

我设置5秒一次,origin和destination 没动总共24个query,到第11个月的时候就被ban了(400)

--- 第 15 楼来自 无敌饺子 的回复 (2026-01-02 09:18:55 PST) ---

只能说NB

--- 第 16 楼来自 AnonAno 的回复 (2026-01-02 09:21:50 PST) ---

loop的话是很有可能ban,但也玄学。这十一个月就ban可能倒霉吧…

不对,看了眼我截图但我好像12月也有400,但我怎么感觉可能是哪里有bug…你再跑一圈试试,有没有成功的? ban应该是access denied 403,而且网页上也会白屏写access denied

--- 第 17 楼来自 One 的回复 (2026-01-02 09:22:35 PST) ---

请允许我问一个小白问题,打开F12去哪里跑这个command?我找到了run - command, 没用啊

--- 第 18 楼来自 AnonAno 的回复 (2026-01-02 09:27:30 PST) ---

打开后右手边最上面or中间应该有个bar可以选tab,选console,滚到最下面有个地方能打字,复制到那里面后按enter。

如果chome console是第一次跑代码跑会报错,会说要你手动输入一行啥,我不记得了。输入后再复制进去跑一次就行

Screenshot 2026-01-02 at 9.26.25 AM2428×418 93.5 KB

Screenshot 2026-01-02 at 9.25.16 AM2416×378 76.2 KB

--- 第 19 楼来自 Corsair 的回复 (2026-01-02 09:27:50 PST) ---

我因为用的是incognito,之前关了,又开了个新的是能跑的

--- 第 21 楼来自 xiaohuli8485 的回复 (2026-01-02 09:51:32 PST) ---

没什么好说的,牛就一个字!

--- 第 22 楼来自 ALousaBao 的回复 (2026-01-02 09:52:55 PST) ---

这什么银卡小号冲钛帖?

--- 第 23 楼来自 Blind 的回复 (2026-01-02 10:16:17 PST) ---

我记得之前有一段时间手动刷都ban

--- 第 24 楼来自 abcdcBTBT 的回复 (2026-01-02 17:23:07 PST) ---

如果可以做到tampermonkey里一键爬应该就是全自动了 ,再加个interface

--- 第 25 楼来自 及时行乐 的回复 (2026-01-02 18:29:47 PST) ---

大佬又开小号冲钛啦

--- 第 26 楼来自 WilliamOne 的回复 (2026-01-02 18:45:19 PST) ---

感谢分享。

--- 第 27 楼来自 simula 的回复 (2026-01-02 19:00:40 PST) ---

技术流啊

--- 第 29 楼来自 AnonAno 的回复 (2026-01-03 07:18:12 PST) ---

[quote=“abcdcBTBT, post:24, topic:471003”]

可以做到tampermonkey里一键

[/quote]

应该可以 今天在travrel 回去改下

--- 第 30 楼来自 Snowerrr 的回复 (2026-01-03 10:10:36 PST) ---

插个眼zs

--- 第 31 楼来自 zhe 的回复 (2026-01-03 10:53:21 PST) ---

银卡会员恐怖如斯,老东西终于把焚决交出来了

--- 第 32 楼来自 AnonAno 的回复 (2026-01-03 21:32:48 PST) ---

为什么我更新不了自己的主楼了。。。救命

@uscreditcardguide

伟大的AI帮助轮椅进化了,这次只要
点击link,安装,运行就行

完全不需要任何developer skills了,连按f12都能省掉

greasyfork.org

JL Award on AA Calendar Scanner

Scans JL award availability on aa.com

效果演示

Screenshot 2026-01-03 at 9.13.23 PM1207×1326 253 KB

题外话
【引用自 未知】:
【泥潭国】【恰饭】想要一个泥潭国惊为天人的餐厅合集 旅行
泥潭国作为本坛御用度假国,坛里攻略和游记也不少。
但作为一个出去玩满脑子只有逛到哪吃到哪吃的P人,这里想要一个单纯的惊为天人的日本餐厅合集。
现在的想法是大家能不能每人推荐 一个and only one 在霓虹吃到的最最惊艳的餐厅,不限地点餐种和价格。但是希望大家最好能以好吃程度来推荐,而不是提供的情绪价值。
但确实众口难调,这里说推荐一个是想保证质量。至于要不要去试试就大家各有所好了。我…
希望抢到票的小伙伴们去了霓虹后留下你最珍贵的回忆,作为一个废物死宅吃货我想吃到泥潭所有的好吃的

下次去泥潭国,如果去的城市有你推荐的餐厅,一天能吃六顿的我大概率会去试试

--- 第 33 楼来自 xjiakskd 的回复 (2026-01-03 21:51:05 PST) ---

太赞了,想问下这里默认是扫描整个月是吗

--- 第 34 楼来自 AnonAno 的回复 (2026-01-03 21:54:37 PST) ---

【引用自 xjiakskd】:
里默认是扫描整个月是吗
对,calendar api好像只能扫整个月。没有加单独扫天是应为这可能会导致request数量暴涨而被快速block掉。如果需要每天的api看flight details需要搭配ip pool,但那就有成本了并且需要一定的技术能力了。但只scan 特定的单天其实也可以(但我有点懒。。。)

--- 第 35 楼来自 bright2000 的回复 (2026-01-03 23:16:36 PST) ---

日期的 01 能改成today+1吗,否则不能搜当月的。
【引用自 AnonAno】:
01

--- 第 36 楼来自 AnonAno 的回复 (2026-01-04 11:05:01 PST) ---

感谢指出。但我现在好像改不了主楼了不知道为啥

--- 第 37 楼来自 WilliamOne 的回复 (2026-01-04 11:26:47 PST) ---

感谢,好用。

--- 第 38 楼来自 Synbiomotif 的回复 (2026-01-04 15:18:07 PST) ---

感谢楼主喂饭。

--- 第 39 楼来自 pengyu 的回复 (2026-02-10 16:30:18 PST) ---

感谢楼主。想问一下楼主我下载了插件但是脚本没有自动弹出来,是被block掉了吗

图像2-10-26 下午4.291920×1243 278 KB

--- 第 40 楼来自 佩洛西 的回复 (2026-02-10 18:23:11 PST) ---

AA/JL 小白,所以,一张票都没有,2月到5月?

--- 第 41 楼来自 zq1095 的回复 (2026-02-10 18:30:05 PST) ---

这这这!这才是我来这个论坛的真谛!!!!!!(当然还有那个xx区,我不说是哪个)

--- 第 42 楼来自 KingGrimlock 的回复 (2026-02-10 18:38:35 PST) ---

正在学习如何出里程票,感谢楼主

--- 第 43 楼来自 jusgsopp 的回复 (2026-02-10 19:27:11 PST) ---

【引用自 AnonAno】:
伟大的AI帮助轮椅进化了,这次只要
你用的是gemina吗,目前都不用古法编程了

我搜索12个月只找到一张TYO-DFW的票,还要转温哥华,退了退了

--- 第 44 楼来自 davidx 的回复 (2026-02-10 19:39:17 PST) ---

此话怎讲?
【引用自 AnonAno】:
现在搜票api不能单独发了,需要cookie和credentials,我们直接从chrome里偷来发api reqest
相当于用的当前session的cookie?但我不登录仍然可以搜票啊 那这样的话意思是只要构造出一个cookie就能匿名发这个请求了?

--- 第 45 楼来自 JamesLin 的回复 (2026-02-14 01:12:16 PST) ---

同, 不知道ui为什么不能自动打开了

--- 第 46 楼来自 cangshuqiuqiuzi 的回复 (2026-03-23 00:16:59 PDT) ---

感谢楼主 楼主好人!! 差评AA为什么那么多幽灵票。。。

--- 第 47 楼来自 xiaohuli8485 的回复 (2026-03-23 13:16:22 PDT) ---

自动化之后确实好用。再请问大佬一下,能不能加个人数选择?或者从code哪里可以改一下?

--- 第 48 楼来自 smartkitten 的回复 (2026-03-23 16:50:20 PDT) ---

太牛了,小白问下mac是一样的使用方法吗

--- 第 49 楼来自 Psych0 的回复 (2026-03-23 19:22:54 PDT) ---

一样的 Chrome fn+f12开console

--- 第 50 楼来自 Nekoangel 的回复 (2026-03-25 12:41:44 PDT) ---

我刚才扫了差不多10个round也被block了,换了个ip还是 block 但是新开浏览器环境要重新验证码登陆 有点麻烦就是

大概 40个calendar request in 10mins

(看起来只ban浏览器环境?)

登陆别的号同ip还是可以搜索

--- 第 51 楼来自 Zhangvivian1 的回复 (2026-03-25 14:19:52 PDT) ---

扫到几个,兴奋的点进去定,结果不是尸体就是幽灵票,求大佬指点破解的办法?

--- 第 52 楼来自 AnonAno 的回复 (2026-03-26 13:30:40 PDT) ---

不用登录就能扫,就是买票的时候要登录不知道会不会被抢走就是了..

--- 第 53 楼来自 AnonAno 的回复 (2026-03-26 18:51:59 PDT) ---

提供几个进阶思路,可以看自己时间和自己能力(其实是calude的能力bushi)慢慢往上加:

加个telegram/discord key,搜到票给自己的一个channel发消息
改成全自动,每隔一段时间扫一下
不要用网页了,用shell script/ python去模拟浏览器
加个ip pool这样可以频繁扫

--- 第 54 楼来自 pengyu 的回复 (2026-03-27 02:06:36 PDT) ---

想问一下楼主怎么做ip pool啊?试着搞了一个,结果被gpt搞的是个假票。让他帮我做ip pool也不肯

--- 第 55 楼来自 zpahai 的回复 (2026-04-04 22:33:22 PDT) ---

IP是不会ban的,只ban浏览器profile。shell script和python没法过Akamai的challenge,必须是自动化浏览器

--- 第 56 楼来自 Iscream 的回复 (2026-04-06 07:32:07 PDT) ---

全自动太容易封了,基本上跑一天就挂了,我自己写了个很复杂的,现在直接跳challenge,还在琢磨怎么破