PHP 从外部配方页面获取 application/ld+json 数据

PHP Get application/ld+json data from external recipe page

有人可以帮助我吗?我一直在到处搜索,但无法找到或生成正确的解决方案。我需要帮助从外部页面提取食谱数据。如果你看一下图像,你会注意到在同一页面上实现了几个 ld+json 标签,但我只需要提取配方数据并以 JSON 格式生成它,并且从那里,我知道如何将它加载到数据库中的 table。

  1. 是页面的URL。
  2. ld-json 标签的位置,虽然在其他页面上有所不同。
  3. 我需要提取并以Json格式打印出来的数据。

我试过这个脚本,但我不确定如何从页面中只获取食谱数据。

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTMLFile('https://www.thecookingcat.com/recipes/fluffy-pancake.php');
libxml_clear_errors();

$recipe = array();
$xpath = new DOMXPath($dom);
$contentDiv = $dom->getElementById('content');
$recipe['title'] = $xpath->evaluate('string(div/h2/a)', $contentDiv);
foreach ($xpath->query('div/div/ul/li', $contentDiv) as $listNode) {
    $recipe['ingredients'][] = $listNode->nodeValue;
}
print_r($recipe);

您的代码似乎解析了页面的复杂 HTML,而不是使用您指定的 ld+json,这将以更简单、更易于访问的方式提供所有必要的数据。

所以,第一个建议,而不是使用 DOMXPath,只需像这样循环页面中的所有脚本:

foreach ($dom->getElementsByTagName('script') as $script) {

然后,为了避免尝试解析真正的 javascript 代码而只考虑 ld+json 内容,请检查 type 属性,如下所示:

if ($script->getAttribute('type') == "application/ld+json") {

您现在可以使用 $script->textContent

访问标签内的文本

通常,您可以直接将 json 解析为对象,但返回的文本有 2 个问题会使 json_decode 失败:

  1. 第一行有注释,我们可以用正则表达式去掉
$json_txt = preg_replace('@/\*.*?\*/@', '', $script->textContent);
  1. 它包含段落中的换行符,我们可以用另一个正则表达式将其删除
$json_txt = preg_replace("/\r|\n/", " ", trim($json_txt));

现在您已正确格式化 json,您可以将其解码为对象。

$json = json_decode($json_txt);

然后您可以轻松访问所有属性。例如,要获取食谱的名称,您可以使用

$json->name

对于成分,您已经有了一个数组,因此您甚至不必循环。

$json->recipeIngredient;

如果您愿意,当然可以将其分配给您自己的数组:

$recipe['title'] = $json->name;
$recipe['ingredients'] = $json->recipeIngredient;

这里是整体代码

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTMLFile('https://www.thecookingcat.com/recipes/fluffy-pancake.php');

$recipe = array();
foreach ($dom->getElementsByTagName('script') as $script) {
    if ($script->getAttribute('type') == "application/ld+json") {
        $json_txt = preg_replace('@/\*.*?\*/@', '', $script->textContent);
        $json_txt = preg_replace("/\r|\n/", " ", trim($json_txt));
        $json = json_decode($json_txt);

        if ($json->{'@type'} == "Recipe") {
            $recipe['title'] = $json->name;
            $recipe['ingredients'] = $json->recipeIngredient;
        }
    }
}