【问题标题】:How to extract href, title, and text data from an <a> tag with a specific class value from scraped html?如何从抓取的html中提取具有特定类值的<a>标签中的href、标题和文本数据?
【发布时间】:2018-04-26 13:56:41
【问题描述】:

我有这个preg_match_all() 的正则表达式,它在 regex101.com 上正确匹配,但在我的代码上却没有。

我试图解析的 html 元素如下所示:

&lt;a class="profile-link" href="CompanyProfile.aspx?PID=4813&amp;amp;country=211&amp;amp;practicearea=0&amp;amp;pagenum=" title="1-844-Iran-Law"&gt;Amin Alemohammad&lt;/a&gt;

在整个 html curl 结果中找到。每个块都有以下例如:

<li style="opacity: 1;">
   <a class="profile-link" href="CompanyProfile.aspx?PID=4813&amp;country=211&amp;practicearea=0&amp;pagenum=" title="1-844-Iran-Law">Amin Alemohammad</a>
   <!--<a class="profile-link" href="javascript:void(0)" title="1-844-Iran-Law">Amin Alemohammad</a>-->
   <img src="/Images/Uploaded/Photos/4813_1844IranLaw.png" style="max-width:140px; max-height:140px">
   <div class="results-profile">
      <h2>Amin Alemohammad</h2>
      <p><strong>Firm:</strong> 1-844-Iran-Law <br> <strong>Country:</strong> USA</p>
   <p class="blue"><strong>Practice Area:</strong> Iranian Desk</p>
   <ul>
      <li class="tel-icon" style="opacity: 1;">Tel: +1-202-465-8692</li>
      <li class="fax-icon" style="opacity: 1;">Fax: +1-202-776-0136</li>
      <li class="email-icon">Email: <a style="position:relative; z-index:9999;" href="mailto:amin@1844iranlaw.com">amin@1844iranlaw.com</a></li>
   </ul>
   </div><!-- results profile -->
      <img class="practice-logo" src="/Images/Uploaded/Logos/4813_1844IranLaw.png" style="max-width:185px; max-height:70px;">
      <a class="results-btn contact-btn" href="CompanyProfile.aspx?PID=4813&amp;country=211&amp;practicearea=0&amp;pagenum=" title="View Full Profile">VIEW FULL PROFILE</a>
      <!--<a class="results-btn contact-btn" href="CompanyProfile.aspx?PID=4813&country=211&practicearea=0&pagenum=" title="1-844-Iran-Law">CONTACT</a>-->
      <a class="results-btn website-btn" href="http://www.1844iranlaw.com" title="www.1844iranlaw.com">VIEW WEBSITE</a>
   </li>
</li>

正则表达式结果

Group 1.    54-58   `4813` // company profile
Group 2.    71-74   `211` // country id
Group 3.    92-93   `0` // practice area
Group 5.    115-129 `1-844-Iran-Law` // company name
Group 6.    131-147 `Amin Alemohammad` // Person's name

我拥有的是:

preg_match_all('/<a class="profile-link" href="CompanyProfile\.aspx\?PID=(.*?)&amp;country=([0-9]{1,}?)&amp;practicearea=([0-9]{1,10}?)&amp;pagenum=\?" title="(.*?)">(.*?)<\/a>/', $result, $match, PREG_PATTERN_ORDER);
dd($match);

返回

array:6 [▼
   0 => []
   1 => []
   2 => []
   3 => []
   4 => []
   5 => []
]

匹配数是正确的 -> 字符串模式中有 5 个匹配,但我不知道为什么它返回空值。

提前感谢您的任何帮助,因为我尝试了很多方法,但不是正确的方法或看到我错过了什么。

【问题讨论】:

  • 在你的正则表达式中有一个\?,它不属于那里,在pagenum=之后。当你删除它工作正常。 /&lt;a class="profile-link" href="CompanyProfile\.aspx\?PID=(.*?)&amp;amp;country=([0-9]{1,}?)&amp;amp;practicearea=([0-9]{1,10}?)&amp;amp;pagenum=\?" title="(.*?)"&gt;(.*?)&lt;\/a&gt;/ 应该是 /&lt;a class="profile-link" href="CompanyProfile\.aspx\?PID=(.*?)&amp;amp;country=([0-9]{1,}?)&amp;amp;practicearea=([0-9]{1,10}?)&amp;amp;pagenum=" title="(.*?)"&gt;(.*?)&lt;\/a&gt;/
  • 在数组中仍然得到相同的空值。
  • 它适用于我使用上述正则表达式和您的示例结果。
  • 只选择那段代码,是的,它有效。但我从 curl 结果的&lt;body&gt;(...)&lt;/body&gt; 中获取全部内容。可能有些东西可能会破坏它并返回空值
  • 我不知道整个内容是什么样的,所以我真的不能帮你调试它。也许&lt;a...&gt;&lt;/a&gt; 之间的内容中有换行符?如果是这样,您可以在正则表达式的末尾添加s modifier。或尝试 DOMDocument 答案。解析 HTML 时,正则表达式为 notoriously bad

标签: php regex dom preg-match-all domparser


【解决方案1】:

您可以使用DOMDocument,而不是使用正则表达式。

要从href 属性中获取值,您可以使用explodeparse_str

$html = <<<HTML
<a class="profile-link" href="CompanyProfile.aspx?PID=4813&amp;country=211&amp;practicearea=0&amp;pagenum=" title="1-844-Iran-Law">Amin Alemohammad</a>
HTML;

$doc = new DOMDocument();
$doc->loadHTML($html);
foreach($doc->getElementsByTagName('a') as $a) {
    if ($a->getAttribute('class') === 'profile-link') {
        $parts = explode('?', $a->getAttribute('href'), 2);
        parse_str($parts[1], $output);

        echo 'Title: ' . $a->getAttribute('title') . '<br>';
        echo 'Text: ' . $a->nodeValue . '<br>';
        echo 'PID: ' . $output['PID'];
        // etc..
    }
}

Demo

【讨论】:

  • 当使用explode()将字符串切成两半时,请将limit值写成2。这确保了explode() 永远不会过度执行,并且它告诉未来的开发人员您的代码的意图是将字符串切成两半。双赢。只是一个建议。
  • @mickmackusa 谢谢你的建议。随意编辑它!
  • 谢谢第四只鸟。它看起来更清洁、更便宜、更高效。我必须承认,到目前为止,我对 DOMDocument 的工作并不多,但会花一些时间在上面。谢谢!
  • 不客气。你也应该看看@mickmackusa 的答案。
【解决方案2】:

代码:(Demo)

$dom = new DOMDocument; 
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$output = [];
foreach ($xpath->evaluate("//a[@class='profile-link']") as $node) {
    parse_str(parse_url($node->getAttribute('href'), PHP_URL_QUERY), $output);
    $output['title'] = $node->getAttribute('title');
    $output['text'] = $node->nodeValue;
}
var_export($output);

输出:

array (
  'PID' => '4813',
  'country' => '211',
  'practicearea' => '0',
  'pagenum' => '',
  'title' => '1-844-Iran-Law',
  'text' => 'Amin Alemohammad',
)

我相信这充分利用了 php 语言的全部美感,DomDocumentXpath 可靠/直接定位合格标记/节点,然后 parse_url()parse_str() 雄辩地将查询字符串数据转换为所需的键值对。

现在您将拥有稳定的东西,没有 hacky str_replace() 调用或正则表达式模式。

【讨论】:

  • 感谢您为此使用了正确的函数,一个用于提取 url 的 XML 解析器,一个用于从 url 中提取查询的 parse_url,以及用于解析该查询的 parse_str,您做到了应该完成,干得好。 :)
  • @McRui 我是否充分回答了你的问题?
【解决方案3】:

好吧,在深入研究问题一段时间后,分析整个 html 以由 preg_match_all() 解析,我只是通过添加几行来替换 html 中的 \t \r \n正则表达式不起作用。

所以解决方案是在preg_match_all()之前添加以下两行:

(...)
$result = curl_exec($curl); // already there

$result = str_replace(["&amp;"], "&", $result); // new
$result = str_replace(["\t", "\r", "\n"], "", $result); // new
$regex = '/<a class="profile-link" href="CompanyProfile\.aspx\?PID=(.*?)&country=([0-9]{1,}?)&practicearea=([0-9]{1,}?)&pagenum=" title="(.*?)">(.*?)<\/a>/s';

preg_match_all($regex, $result, $match, PREG_SET_ORDER);

然后,我在正则表达式中强制使用&amp;amp; 字符而不是链接中的&amp;amp;。它就像魅力一样工作!

比你们所有的人都伸出援助之手!

【讨论】:

  • 您正在解析 HTML,因此您应该使用像 DomDocument 这样的 html 解析器来提高可靠性。与其调用两次str_replace(),不如调用一次并编写一个search 字符串数组和一个replace 字符串数组。也就是说,如果您的回答解决了您的问题,请将您的回答打上绿色勾号,以便系统认为此页面已解决。
  • 嗨 mickmackusa,感谢您的提示。发布答案时,我仍然无法授予答案绿色勾号。谢谢。
  • html中只有一个profile-link类吗?或者您是否可能在单个页面中找到多个匹配项? (我将发布一个聪明的新方法)
  • 不要使用 str_replace,我们有一个适当的函数来解码 html,它被称为 html_entity_decode - 但是,也不要使用正则表达式,使用适当的 DOM 解析器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 1970-01-01
  • 2021-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-16
相关资源
最近更新 更多