【问题标题】:Extracting javascript object from html using regex & php使用正则表达式和 php 从 html 中提取 javascript 对象
【发布时间】:2018-10-17 19:45:23
【问题描述】:

我正在尝试从包含常用 HTML 标记的页面中提取特定的 JavaScript 对象。

我尝试使用正则表达式,但当 HTML 包含换行符时,我似乎无法正确解析 HTML。

可以在这里看到一个例子:https://regex101.com/r/b8zN8u/2

我尝试提取的 HTML 如下所示:

<script>
  DATA.tracking.user = { 
      age: "19", 
      name: "John doe" 
  }
</script>

使用以下正则表达式:DATA.tracking.user=(.*?)}

<?php
$re = '/DATA.tracking.user = (.*?)\}/m';
$str = '<script>
           DATA.tracking.user = { age: "19", name: "John doe" }
        </script>';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

如果我在没有任何换行符的情况下解析 DATA.tracking.user = { age: "19", name: "John doe" },那么它可以正常工作,但如果我尝试解析:

DATA.tracking.user = { 
      age: "19", 
      name: "John doe" 
  }

它不喜欢处理换行符。

任何帮助将不胜感激。

谢谢。

【问题讨论】:

标签: php regex parsing


【解决方案1】:

您需要在模式中指定空格 (\s) 以解析包含换行符的 javascript 代码。

例如,如果您使用以下代码:

<?php
$re = '/DATA.tracking.user = \{\s*.*\s*.*\s*\}/';
$str = '<script>
  DATA.tracking.user = {
      age: "19",
      name: "John doe"
  }
</script>';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
print_r($matches[0]);
?>

你会得到以下输出:

Array
(
    [0] => DATA.tracking.user = {
      age: "19",
      name: "John doe"
  }
)

【讨论】:

    【解决方案2】:

    解决问题的简单方法是使用s 模式修饰符来命令.(任何字符)也匹配换行符——默认情况下不匹配。

    你应该:

    • 避开字面上的点。
    • 在您的捕获组之外写入\{
    • 省略 m 模式修饰符,因为您没有使用锚。

    ...但是...

    如果这是我的任务并且我要从提取的字符串中处理数据,我可能会在提取时使用\G 的强大功能分解组件。

    代码:(Demo) (Pattern Demo)

    $htmls[] = <<<HTML
    DATA.tracking.user = { age: "19", name: "John doe", int: 55 } // This works
    HTML;
    
    $htmls[] = <<<HTML
    DATA.tracking.user = { 
        age: "20", 
        name: "Jane Doe",
        int: 49
    } // This does not works
    HTML;
    
    foreach ($htmls as $html) {
        var_export(preg_match_all('~(?:\G(?!^),|DATA\.tracking\.user = \{)\s+([^:]+): (\d+|"[^"]*")~', $html, $out, PREG_SET_ORDER) ? $out : []);
        echo "\n --- \n";
    }
    

    输出:

    array (
      0 => 
      array (
        0 => 'DATA.tracking.user = { age: "19"',
        1 => 'age',
        2 => '"19"',
      ),
      1 => 
      array (
        0 => ', name: "John doe"',
        1 => 'name',
        2 => '"John doe"',
      ),
      2 => 
      array (
        0 => ', int: 55',
        1 => 'int',
        2 => '55',
      ),
    )
     --- 
    array (
      0 => 
      array (
        0 => 'DATA.tracking.user = { 
        age: "20"',
        1 => 'age',
        2 => '"20"',
      ),
      1 => 
      array (
        0 => ', 
        name: "Jane Doe"',
        1 => 'name',
        2 => '"Jane Doe"',
      ),
      2 => 
      array (
        0 => ',
        int: 49',
        1 => 'int',
        2 => '49',
      ),
    )
     --- 
    

    现在您可以简单地迭代匹配并使用[1](键)和[2](值)。这是一个基本解决方案,可以进一步定制以适合您的项目数据。诚然,这不考虑包含转义双引号的值。添加此功能不会有任何问题。考虑更复杂的值类型可能更具挑战性。

    【讨论】:

    • mickmackusa,感谢您抽出宝贵时间提供帮助。我接受了这个作为答案,因为这最适合我的要求,并且使使用 $key $values 变得更加容易。
    【解决方案3】:

    您需要将“s”修饰符添加到您的正则表达式的末尾 - 否则,“。”不包括换行符。见this

    s (PCRE_DOTALL)

    如果设置了此修饰符,则模式中的点元字符匹配所有字符,包括换行符。没有它,换行符被排除在外。这个修饰符等价于 Perl 的 /s 修饰符。诸如 [^a] 之类的否定类始终匹配换行符,与此修饰符的设置无关。

    所以基本上将您的正则表达式更改为:

    '/DATA.tracking.user = (.*?)\}/ms'
    

    此外,您应该引用其他点(否则您将匹配“DATAYtrackingzZuser”。所以...

    '/DATA\.tracking\.user = (.*?)\}/ms'
    

    我还要添加大括号,而不是在等号周围强制使用单个空格,所以:

    '/DATA\.tracking\.user\s*=\s*\{(.*?)\}/ms'
    

    【讨论】:

    • wordragon,感谢您为我遇到的问题提供支持,虽然这有效并让我的刮刀运行,但我接受了 mickmackusa 的回答,因为他的回答让我在使用刮刀时更轻松关键值。谢谢。
    【解决方案4】:

    由于您似乎无论如何都在抓取/阅读页面(因此您有一个本地副本),您可以简单地将 HTML 页面中的所有换行符替换为空白字符,然后它应该可以完美地工作,甚至无需更改您的脚本。

    有关 ascii 值,请参阅此内容:
    https://www.techonthenet.com/ascii/chart.php

    【讨论】:

      猜你喜欢
      • 2018-02-03
      • 2016-10-13
      • 2015-08-10
      • 1970-01-01
      • 2021-04-14
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多