跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://docs.brightdata.com/llms.txt

Use this file to discover all available pages before exploring further.

本指南介绍 Bright Data Scraper Studio 团队推荐的编码模式,帮助您在 IDE 中编写快速、可靠的爬虫。每个章节都对比一种常见错误与推荐写法,并解释原因。

如何可靠地检测无效页面?

使用 navigate() 时,添加 dead_page() 条件,避免爬虫对不存在的页面进行重试。Bright Data Scraper Studio 会自动将 HTTP 404 响应标记为无效,但许多站点会返回 200 加一个”未找到”模板,因此需要您自行检测。 不要把 wait() 包在 try/catch 中,再从 catch 块里调用 dead_page()wait() 抛错只能说明选择器在超时窗口内未出现,并不能证明页面真的不存在。
try {
  // 即使页面已无效,也会等待 30 秒查找 'ok-selector'
  wait('ok-selector');
} catch (e) {
  // 仅凭 wait 超时无法证明页面无效
  dead_page("Page doesn't exist");
}

如何减少对浏览器的请求次数?

clicktypeel_existsel_is_visiblewaitwait_visible 等交互命令都会向浏览器发送一次请求。请把多个选择器合并到一次调用中,而不是串联多次调用。
if (!(el_exists('#price1')) || el_exists('#price2')
  || el_exists('#price3') || el_exists('#discount'))
{
    dead_page('No price found');
}

如何在不阻碍并行化的前提下处理分页?

当站点有分页结果、您又需要每一页的数据时,应在根页面上为每一页调用一次 rerun_stage()。不要在每页内顺序爬取分页时再调用 rerun_stage(),那样会把工作串行化,Bright Data Scraper Studio 无法并行处理请求。
navigate(input.url);
let $ = html_load(html());
let next_page_url = $('.next_page').attr('href');
rerun_stage({url: next_page_url});

如何在不等待的情况下关闭弹窗?

使用 close_popup('popup_selector', 'close_button_selector') 注册一个后台监视器,让它在弹窗出现时自动关闭。不要在每次交互前用 wait_visible() 轮询弹窗:弹窗可能随时出现,而显式等待会给每一步都增加延迟。
navigate('https://example.com');
try {
  wait_visible('.cky-btn-accept', {timeout: 5000});
  click('.cky-btn-accept');
} catch (e) {
    console.log('Accept cookies button does not exist, continue');
}

解析前如何等待已标记的响应?

使用 tag_response() 捕获后台 API 调用后,紧接着调用 wait_for_parser_value() 以确保请求在读取 parser 之前已经完成。否则,解析器可能在响应到达之前就运行,导致 parser.<字段>undefined
tag_response('product', /api\/product/);
navigate('https://example.com');

// 解析器代码:
// 请求可能尚未完成,product 可能是 undefined
let {product} = parser;
return product.data;

是否应该抛出自定义错误信息?

不应该。让 Bright Data Scraper Studio 的内置错误自然冒出。内置错误会附带选择器、超时时间和阶段信息,比手写的 “Page not loaded properly” 更有用。只有当您要检查平台无法自行识别的、领域相关的条件时(例如缺少产品标题),才需要抛出自定义错误。
try {
  wait('selector1');
  // some code
  wait('selector2');
  // some code
} catch (e) {
  throw "Page not loaded properly"
}

如何在不过度延长超时的前提下应对响应慢的站点?

大多数等待保持默认的 30 秒超时即可。如果某个特定页面长期较慢,可将超时上调到 45 或 60 秒。不要超过 60 秒:原因通常是 peer 较慢,而 Bright Data Scraper Studio 在页面报告超时错误后会自动用新的 peer 会话重试。
// 120 秒太长;平台无法回收卡住的 peer
wait('selector', {timeout: 120000});

是否应该自己写重试循环?

不应该。Bright Data Scraper Studio 在任务层面会用新的 peer 会话进行重试。在爬虫内部写自定义重试循环会复用同一个会话,而这正是第一次失败的根源。报告错误,把重试交给平台。
let counter = input.counter || 5;
while (counter > 1) {
  try {
    wait('selector', {timeout: 500});
    click('selector');
    type('selector');
    // some code
    break;
  } catch (e) {
    // rerun_stage 会创建新会话,但这种模式会消耗额外 CPM
    return rerun_stage({...input, counter: --counter});
  }
}

是否应该在解析器表达式外面包 try/catch?

不应该。改用可选链(?.)和空值合并(??)。属性访问外面包一层静默的 try/catch 会掩盖真实的 bug;包在 wait() 外的 try/catch 则会浪费浏览器时间。
try {
  const example = obj.prop;
} catch (e) {}

解析器代码中如何从一组元素提取值?

使用 toArray().map() 而不是 each()。前者更短、返回真正的数组,并且作为单一表达式可读性更好。
const links = [];
$('.card.product-wrapper').each(function (i, el) {
  links.push({url: $(this).find('h4 a').attr('href')});
})
return links;

解析器代码中如何规范化文本?

调用 $(selector).text_sane()。Bright Data Scraper Studio 在 Cheerio 原型上扩展了这个方法:它会把每一段连续空白折叠为单个空格并对结果进行 trim。对于数字提取,使用正则去掉非数字。
$.prototype.clearText = function () {
  return this.text().replace(/\s+/g, ' ').trim();
}

相关内容

Scraper Studio 函数参考

Bright Data Scraper Studio 交互命令与解析器命令的完整参考

Worker 类型

为您的爬虫在 Browser worker 与 Code worker 之间做选择