You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 01:47:43