如何用NodeJS免Selenium实现Bloomberg登录后抓取付费文章
整体目标
使用NodeJS,通过用户凭据登录Bloomberg,以登录用户身份抓取内容,优先不使用Selenium(因速度较慢)。
核心问题
如何登录Bloomberg并保持登录状态,以此抓取文章完整内容?寻求可行方案或替代思路,同时希望避免每次抓取都重新登录。
当前方案
目前可通过Axios.get设置user-agent结合Cheerio(便捷类选择器)抓取非付费墙内容。以文章https://www.bloomberg.com/news/articles/2023-06-28/doordash-introduces-hourly-minimum-rate-option-for-dashers为例,未登录仅能获取2段内容,订阅账号登录后可获取7段。
遇到的问题
尝试向https://www.bloomberg.com/account/signin发送POST请求登录失败,代码如下:
import axios from 'axios'; import { CookieJar } from 'tough-cookie'; import { wrapper } from 'axios-cookiejar-support'; const cookieJar = new CookieJar(); const client = wrapper(axios.create({ cookieJar })); const loginData = { username: 'my_username', password: 'my_password' }; // login client.post('https://www.bloomberg.com/account/signin', loginData, { jar: cookieJar, withCredentials: true }).then((response) => { console.log(response.data); }).catch((error) => { if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); console.log("path1") } else if (error.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of // http.ClientRequest in Node.js console.log(error.request); console.log("path2") } else { // Something happened in setting up the request that triggered an Error console.log('Error', error.message); console.log("path3") } console.log(error.config); console.log("path4"); });
观察登录页面请求未发现POST请求(仅GET),发送POST请求返回405错误(请求方法不被支持)。
1. 分析Bloomberg登录流程
Bloomberg的登录页面并非直接接受POST请求到/account/signin,实际登录请求由专门的身份验证服务处理,核心流程为:
- 访问登录页获取会话cookie和csrf token
- 提交凭据到专属认证接口
- 处理跳转完成会话验证
2. 修正登录请求流程
步骤一:获取登录页会话信息与csrf token
先发送GET请求登录页面,解析页面中的csrf token(通常在meta标签或表单隐藏字段中),同时保存会话cookie:
import axios from 'axios'; import { CookieJar } from 'tough-cookie'; import { wrapper } from 'axios-cookiejar-support'; import cheerio from 'cheerio'; const cookieJar = new CookieJar(); const client = wrapper(axios.create({ cookieJar, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } })); async function getLoginToken() { const loginPageRes = await client.get('https://www.bloomberg.com/account/signin'); const $ = cheerio.load(loginPageRes.data); // 实际字段名需根据页面调整,此处为示例 const csrfToken = $('meta[name="csrf-token"]').attr('content'); return csrfToken; }
步骤二:提交凭据到正确的认证接口
通过浏览器开发者工具追踪实际登录请求,Bloomberg通常将登录请求发送到类似https://accounts.bloomberg.com/auth/v1/login的专用接口,需携带csrf token、用户名密码及正确请求头:
async function login(username, password) { const csrfToken = await getLoginToken(); const loginRes = await client.post('https://accounts.bloomberg.com/auth/v1/login', { username, password, csrfToken, rememberMe: true }, { headers: { 'X-CSRF-Token': csrfToken, 'Content-Type': 'application/json' } }); // 可通过返回状态或cookie中的认证标识判断登录是否成功 console.log('登录状态:', loginRes.status === 200); }
3. 保持登录状态
- 登录成功后,cookieJar会自动保存认证cookie,后续请求直接复用同一个client实例即可
- 可将cookieJar序列化保存到本地文件,下次启动时加载,避免重复登录:
import fs from 'fs'; // 保存cookie到文件 async function saveCookies() { const cookieStr = await cookieJar.getCookieString('https://www.bloomberg.com'); fs.writeFileSync('./bloomberg_cookies.txt', cookieStr); } // 加载本地cookie async function loadCookies() { if (fs.existsSync('./bloomberg_cookies.txt')) { const cookieStr = fs.readFileSync('./bloomberg_cookies.txt', 'utf8'); await cookieJar.setCookie(cookieStr, 'https://www.bloomberg.com'); } }
4. 抓取付费内容
登录状态验证通过后,直接使用client实例请求文章页面,用Cheerio解析完整内容:
async function fetchArticle(url) { await loadCookies(); // 可通过检查cookie中的认证标识判断是否需重新登录 const articleRes = await client.get(url); const $ = cheerio.load(articleRes.data); // 需根据页面结构调整内容选择器,此处为示例 const paragraphs = $('.article-body__content p').map((i, el) => $(el).text()).get(); console.log('获取段落数:', paragraphs.length); return paragraphs; } // 使用示例 fetchArticle('https://www.bloomberg.com/news/articles/2023-06-28/doordash-introduces-hourly-minimum-rate-option-for-dashers');
注意事项
- Bloomberg的认证接口可能随时间更新,需定期通过开发者工具确认最新接口地址和参数
- 需模拟真实浏览器的请求头,避免被识别为爬虫
- 频繁请求易触发反爬机制,建议添加合理的请求间隔
内容的提问来源于stack exchange,提问作者Carlson

