【问题标题】:How to parse an HTML page using PHP?如何使用 PHP 解析 HTML 页面?
【发布时间】:2010-08-21 13:21:12
【问题描述】:

使用 PHP 解析 HTML / JS 代码以获取信息。

www.asos.com/Asos/Little-Asos-Union-Jack-T-Shirt/Prod/pgeproduct.aspx?iid=1273626

看看这个页面,这是一家儿童服装店。这是他们的项目之一,我想指出尺寸部分。我们在这里需要做的是获取该项目的所有尺寸并检查尺寸是否可用。目前该商品的所有尺寸为:

3-4 years
4-5 years
5-6 years
7-8 years

你怎么知道尺寸是否可用?

现在先看看这个页面,然后再检查一下尺寸:

www.asos.com/Ralph-Lauren/Ralph-Lauren-Long-Sleeve-Big-Horse-Stripe-Rugby-Top/Prod/pgeproduct.aspx?iid=1111751

此商品有以下尺寸:

12 months
18 months - Not Available
24 months

您可以看到 18 个月的尺码不可用,它由尺码旁边的“不可用”文本指示。

我们需要做的是转到一个项目的页面,获取尺寸并检查每个尺寸的可用性。如何在 PHP 中做到这一点?

编辑:

添加了一个工作代码和一个要解决的新问题。

工作代码,但需要更多工作:

<?php

function getProductVariations($url) {

  //Use CURL to get the raw HTML for the page
  $ch = curl_init();
  curl_setopt_array($ch,
    array(
      CURLOPT_RETURNTRANSFER=>true,
      CURLOPT_HEADER => false,
      CURLOPT_URL => $url
    )
  );
  $raw_html = curl_exec($ch);

  //If we get an invalid response back from the server fail
  if ($raw_html===false) {
    throw new Exception(curl_error($ch));
  }

  curl_close($ch);

  //Find the variation JS declarations and extract them
  $raw_variations = preg_match_all("/arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct\[[0-9]+\].*Array\((.*)\);/",$raw_html,$raw_matches);

  //We are done with the Raw HTML now
  unset($raw_html);

  //Check that we got some results back
  if (is_array($raw_matches) && isset($raw_matches[1]) && sizeof($raw_matches[1])==$raw_variations && $raw_variations>0) {

    //This is where the matches will go
    $matches = array();

    //Go through the results of the bracketed expression and convert them to a PHP assoc array
    foreach($raw_matches[1] as $match) {

      //As they are declared in javascript we can use json_decode to process them nicely, they just need wrapping
      $proc=json_decode("[$match]");

      //Label the fields as best we can
      $proc2=array(
        "variation_id"=>$proc[0],
        "size_desc"=>$proc[1],
        "colour_desc"=>$proc[2],
        "available"=>(trim(strtolower($proc[3]))=="true"),
        "unknown_col1"=>$proc[4],
        "price"=>$proc[5],
        "unknown_col2"=>$proc[6],       /*Always seems to be zero*/
        "currency"=>$proc[7],
        "unknown_col3"=>$proc[8],
        "unknown_col4"=>$proc[9],       /*Negative price*/
        "unknown_col5"=>$proc[10],      /*Always seems to be zero*/
        "unknown_col6"=>$proc[11]       /*Always seems to be zero*/
      );

      //Push the processed variation onto the results array
      $matches[$proc[0]]=$proc2;

      //We are done with our proc2 array now (proc will be unset by the foreach loop)
      unset($proc2);
    }

    //Return the matches we have found
    return $matches;

  } else {
    throw new Exception("Unable to find any product variations");

  }
}


//EXAMPLE USAGE
try {
  $variations = getProductVariations("http://www.asos.com/Asos/Prod/pgeproduct.aspx?iid=803846");

  //Do something more useful here
  print_r($variations);


} catch(Exception $e) {
  echo "Error: " . $e->getMessage();
}

?>

上面的代码有效,但是当产品需要您在显示尺寸之前先选择颜色时,就会出现问题。

喜欢这个:

http://www.asos.com/Little-Joules/Little-Joules-Stewart-Venus-Fly-Trap-T-Shirt/Prod/pgeproduct.aspx?iid=1171006

知道该怎么做吗?

【问题讨论】:

  • 我刚刚发现选择大小的选项是由 AJAX 填充的。如您所见,这是尺寸选择 DIV。填充此 DIV 的信息显然来自与后端脚本的 AJAX 交互。 “不可用”一词不在 HTML 中,但当您打开 SELECT 表单控件时,它们会清楚地呈现在屏幕上。所以它们以其他方式放入 DOM 中。 fopen 和 file_get_contents 在这里还能用吗?

标签: php html parsing html-parsing


【解决方案1】:

解决方案:

    function curl($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
        return curl_exec($ch);
        curl_close ($ch);
    }

$html = curl('http://www.asos.com/pgeproduct.aspx?iid=1111751');

preg_match_all('/arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct\[(.*?)\] \= new Array\((.*?),\"(.*?)\",\"(.*?)\",\"(.*?)\"/is',$html,$bingo);

echo print_r($bingo);

链接:http://debconf11.com/stackoverflow.php

你现在靠自己了:)

EDIT2:

好的,我们已经接近解决方案了......

<script type="text/javascript">var arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct = new Array;
arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct[0] = new Array(1164,"12 months","SailingOrange","True","","59.00","0.00","£","","-59.00","0.00","0");
arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct[1] = new Array(1165,"18 months","SailingOrange","False","","59.00","0.00","£","","-59.00","0.00","0");
arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct[2] = new Array(1167,"24 months","SailingOrange","True","","59.00","0.00","£","","-59.00","0.00","0");
</script>

它不是通过 ajax 加载的,而是数组在 javascript 变量中。可以用PHP来解析这个,可以清楚的看到18个月是一个False,表示不可用。

编辑:

这些尺寸是通过 javascript 加载的,因此您无法解析它们,因为它们不存在。 我只能提取这个...

<select name="drpdwnSize" id="ctl00_ContentMainPage_ctlSeparateProduct_drpdwnSize" onchange="drpdwnSizeChange(this, 'ctl00_ContentMainPage_ctlSeparateProduct', arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct);">
<option value="-1">Select Size</option>
</select>

您可以通过嗅探 JS 来检查是否可以根据产品 id 加载尺寸。


首先你需要:http://simplehtmldom.sourceforge.net/ 忘记 file_get_contents(),它比 cURL 慢约 5。

然后你解析这段代码(html with id ctl00_ContentMainPage_ctlSeparateProduct_drpdwnSize)

        <select id="ctl00_ContentMainPage_ctlSeparateProduct_drpdwnSize" name="ctl00$ContentMainPage$ctlSeparateProduct$drpdwnSize" onchange="drpdwnSizeChange(this, 'ctl00_ContentMainPage_ctlSeparateProduct', arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct);">

        <option value="-1">Select Size</option><option value="1164">12 months</option><option value="1165">18 months - Not Available</option><option value="1167">24 months</option></select>

然后您可以使用 preg_match()、explode()、str_replace() 和其他方法来过滤掉您想要的值。我可以写但是我现在没有时间:)

【讨论】:

  • 实际使用 DOM 而不是字符串解析的建议第三方替代方案:phpQueryZend_DomQueryPathFluentDom
  • 我还发现尺寸选择是由 javascript 填充的。我现在更迷茫了,什么是嗅探 JS?
  • 要检查从哪个脚本(服务器端)加载的大小,我试图找到,但这只是一团糟。它有大量的 JS,我不确定它是否需要。请稍候...
  • 现在你只需要从数组中获取数据。
  • 嗨韦巴托!我能够使用 cURL 函数提出与您的代码类似的代码,但您的代码要精简得多。我编辑了我的原始帖子并发布了我自己的代码。我也添加了要解决的新问题,也许您可​​以提供帮助并提出解决方法? --------------- 上面的代码有效,但是当产品需要您在显示尺寸之前先选择颜色时,就会出现问题。喜欢这个:asos.com/Little-Joules/… 知道该怎么做吗?
【解决方案2】:

获取 URL 内容的最简单方法是依赖 fopen 包装器,只需将 file_get_contents 与 URL 一起使用。您可以使用 tidy 扩展来解析 HTML 并提取内容。 http://php.net/tidy

【讨论】:

    【解决方案3】:

    您可以使用 fopen()file_get_contents() 下载文件,正如 Raoul Duke 所说,但如果您有 JavaScript DOM 模型的经验,DOM extension 可能比 Tidy 更易于使用。

    我知道在 PHP 中默认启用 DOM 扩展,但我有点不确定 Tidy 是否启用(手册页只说它是“捆绑的”,所以我怀疑它可能未启用)。

    【讨论】:

      猜你喜欢
      • 2011-07-30
      • 1970-01-01
      • 2011-09-12
      • 2011-11-14
      • 2014-01-08
      • 2012-12-18
      • 2010-12-03
      相关资源
      最近更新 更多