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

JS新手求助:抓取无结构化食谱网站食材时代码返回异常

解决无结构化食谱网站的食材抓取问题

嘿,我完全懂你现在的头疼——没有清晰类名/ID的无结构化食谱网站,对JS爬虫新手来说简直是绕不开的坎!别慌,咱们一步步拆解问题,把食材数据给揪出来。

首先,先搞清楚你代码返回true/false/undefined的核心原因:你可能用了不匹配的DOM选择器,或者没找准食材所在的文本/列表块,甚至遇到了动态加载的内容。下面是具体的解决步骤:

第一步:手动定位食材在DOM中的规律

先打开浏览器开发者工具(按F12),找到食谱页面里的食材区域,仔细观察:

  • 食材是不是在<ul>/<ol>列表里?哪怕列表本身没有类名,它的父元素或者前面的标题(比如“食材”“Ingredients”)有没有独特的文本特征?
  • 有没有可能食材是混在段落文本里,用换行、分号或者符号分隔的?

比如很多食谱网站会在食材列表前放一段类似“食材:”的文本,这就是我们可以利用的锚点。

第二步:基于文本特征的DOM查询(核心方案)

因为没有特殊类名,我们可以用XPath匹配包含特定文本的元素,再定位到它后面的食材列表。举个具体的代码例子:

// 1. 用XPath找到包含"食材"(或"Ingredients")的标题元素
const ingredientHeader = document.evaluate(
  '//*[contains(text(), "食材")]', // 替换成你看到的标题文本,比如英文站用"Ingredients"
  document,
  null,
  XPathResult.FIRST_ORDERED_NODE_TYPE,
  null
).singleNodeValue;

// 2. 定位标题后面的食材列表(假设是ul/ol,根据实际DOM调整)
const ingredientList = ingredientHeader?.nextElementSibling;

// 3. 提取列表里的食材文本
if (ingredientList) {
  const ingredients = Array.from(ingredientList.querySelectorAll('li'))
    .map(item => item.textContent.trim());
  console.log('抓到的食材:', ingredients);
} else {
  console.log('没找到食材列表,请检查DOM结构');
}

如果食材不是在列表里,而是混在段落中,比如用换行分隔,那可以这样提取:

// 找到包含食材的段落元素(可以结合XPath定位)
const ingredientPara = document.evaluate(
  '//p[contains(text(), "食材")]',
  document,
  null,
  XPathResult.FIRST_ORDERED_NODE_TYPE,
  null
).singleNodeValue;

if (ingredientPara) {
  // 按换行分割文本,过滤空行后整理
  const ingredients = ingredientPara.textContent.split('\n')
    .filter(line => line.trim() !== '')
    .map(line => line.trim().replace(/^\d+\.|\*|\-/, '')); // 去掉开头的序号/符号
  console.log('抓到的食材:', ingredients);
}

第三步:处理动态加载的内容

如果你的代码直接查DOM返回undefined,很可能食材是页面加载后通过JS动态渲染的。这时候我们可以直接抓取页面的原始HTML,再用DOMParser解析:

async function fetchRecipeIngredients() {
  try {
    // 发送请求获取页面HTML(记得替换成目标食谱的URL)
    const response = await fetch('https://justanotherrecipeblog.tumblr.com/your-recipe-post-url', {
      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'
      }
    });
    const html = await response.text();

    // 解析HTML为DOM文档
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');

    // 重复之前的XPath查询逻辑
    const ingredientHeader = doc.evaluate(
      '//*[contains(text(), "Ingredients")]',
      doc,
      null,
      XPathResult.FIRST_ORDERED_NODE_TYPE,
      null
    ).singleNodeValue;

    if (ingredientHeader) {
      const list = ingredientHeader.nextElementSibling;
      const ingredients = Array.from(list.querySelectorAll('li')).map(li => li.textContent.trim());
      console.log('抓到的食材:', ingredients);
    }
  } catch (error) {
    console.error('请求出错:', error);
  }
}

// 调用函数
fetchRecipeIngredients();

几个重要的提醒

  • 先检查目标网站的robots.txt(比如https://justanotherrecipeblog.tumblr.com/robots.txt),确保允许抓取相关内容,避免合规问题。
  • 如果遇到403/请求被拦截,记得在fetch里设置合理的User-Agent头,模拟普通浏览器请求。
  • 不同食谱的DOM结构可能略有差异,需要根据实际页面调整XPath或选择器逻辑——多试几次开发者工具里的元素查询,确认选择器能准确命中目标。

内容的提问来源于stack exchange,提问作者Samuel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:09:46