preg_match 在不同的标签中
preg_match with in different tags
我需要一些帮助。我正在尝试从网站上抓取一些特定数据。
<tbody>
<tr style="mso-yfti-irow: 1;">
<td style="width: 184.4pt; border: none; border-left: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="307">
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Certifikat springer 1000m</p>
</td>
<td style="width: 44.7pt; border: none; border-right: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="75">
<p class="MsoNormal" style="margin-bottom: .0001pt; text-align: right; line-height: normal;" align="right">90,-</p>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="width: 184.4pt; border: none; border-left: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="307">
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Certifikat springer 1200m</p>
</td>
<td style="width: 44.7pt; border: none; border-right: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="75">
<p class="MsoNormal" style="margin-bottom: .0001pt; text-align: right; line-height: normal;" align="right">100,-</p>
</td>
</tr>
</tbody>
我想要的是从 mos-yfti-irow1 获得 "Certifikat springer 1000" 和从下一个 TD 获得 90,-。但我不想在此输出中从 mos-yfti-irow2 获取数据。
我想开发一些东西,让人们可以比较我们体育团体与不同俱乐部的某些活动的价格。我不太确定该怎么做。
这是我目前拥有的,但无法真正发挥作用
<?php
$file_string = file_get_contents('http://www.mfkviborg.dk/index.php? option=com_content&view=article&id=21&Itemid=151');
preg_match_all('/<p class="MsoNormal" style="margin-bottom: .0001pt;(.*)">(.*)<\/p>/i', $file_string, $links);
?>
<p><strong>Links:</strong> <em>(Name - Link)</em><br />
<?php
echo '<ol>';
for($i = 0; $i < count($links[1]); $i++) {
echo '<li>' . $links[2][$i] . ' - ' . $links[1][$i] . '</li>';
}
echo '</ol>';
?>
</p>
有什么线索吗?
几个问题:
.
不匹配换行符,除非您在正则表达式末尾指定 s
修饰符。所以应该加上。
.*
是贪心的,所以会尽可能匹配包括一些中间的</p>
。它不应该那样做,所以添加一个 ?
(在这两种情况下)
问题不大,但仍然值得改变:
第一个捕获组可能没有给你有用的信息,所以去掉那里的括号。
.0001
中的.
被当作任意字符,所以要转义。一种方法是把它写成 [.]
这给你这行代码:
preg_match_all('/<p class="MsoNormal" style="margin-bottom: [.]0001pt;.*?">(.*?)<\/p>/is',
$file_string, $links);
使用DOM解析器
请注意,如果您的来源 HTML 只是略有变化(额外的间距或将双引号更改为单引号,或交换属性的位置...),您将遇到问题,并被要求进行调整代码。
使用DOMDocument interface together with a DOMXPath query要好得多。这是它的工作原理:
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($file_string, LIBXML_NOCDATA | LIBXML_NOWARNING | LIBXML_NOERROR );
libxml_use_internal_errors(false);
$xpath = new DOMXPath($doc);
$nodes = $xpath->query("//p[contains(@class, 'MsoNormal') and contains(@style, 'margin-bottom: .0001pt')]");
foreach ($nodes as $node) {
echo $node->textContent . "\n";
}
您也可以使用 load
方法代替 loadHTML
方法,并将 URL 作为第一个参数传递。
跟进
您在评论中要求通过 tr
和 style
属性中的 mso-yfti-irow
进一步过滤输出:
$nodes = $xpath->query("//tr[contains(@style, 'mso-yfti-irow')]//p[contains(@class, 'MsoNormal') and contains(@style, 'margin-bottom: .0001pt')]");
正如其他人所说,请改用像样的解析器,例如DOMDocument()
:
<?php
# set up the dom
$dom = new DOMDocument();
$dom->loadHTML($your_data_here, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);# | LIBXML_COMPACT | LIBXML_NOENT );
# set up the xpath
$xpath = new DOMXPath($dom);
foreach ($xpath->query("//tr[contains(@style, 'mso-yfti-irow: 1')]") as $row) {
$text = $xpath->query("td/p/text()", $row);
$certificate = $text[0]->nodeValue;
$price = $text[1]->nodeValue;
echo "$certificate | $price\n";
}
?>
这会产生您的示例字符串:
Certifikat springer 1000m | 90,-
该代码片段设置了 DOM
并随后使用 xpath
表达式对其进行查询,请参阅 PHP.net
.
上的文档
我需要一些帮助。我正在尝试从网站上抓取一些特定数据。
<tbody>
<tr style="mso-yfti-irow: 1;">
<td style="width: 184.4pt; border: none; border-left: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="307">
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Certifikat springer 1000m</p>
</td>
<td style="width: 44.7pt; border: none; border-right: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="75">
<p class="MsoNormal" style="margin-bottom: .0001pt; text-align: right; line-height: normal;" align="right">90,-</p>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="width: 184.4pt; border: none; border-left: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="307">
<p class="MsoNormal" style="margin-bottom: .0001pt; line-height: normal;">Certifikat springer 1200m</p>
</td>
<td style="width: 44.7pt; border: none; border-right: solid windowtext 1.5pt; padding: 0cm 5.4pt 0cm 5.4pt;" valign="top" width="75">
<p class="MsoNormal" style="margin-bottom: .0001pt; text-align: right; line-height: normal;" align="right">100,-</p>
</td>
</tr>
</tbody>
我想要的是从 mos-yfti-irow1 获得 "Certifikat springer 1000" 和从下一个 TD 获得 90,-。但我不想在此输出中从 mos-yfti-irow2 获取数据。
我想开发一些东西,让人们可以比较我们体育团体与不同俱乐部的某些活动的价格。我不太确定该怎么做。
这是我目前拥有的,但无法真正发挥作用
<?php
$file_string = file_get_contents('http://www.mfkviborg.dk/index.php? option=com_content&view=article&id=21&Itemid=151');
preg_match_all('/<p class="MsoNormal" style="margin-bottom: .0001pt;(.*)">(.*)<\/p>/i', $file_string, $links);
?>
<p><strong>Links:</strong> <em>(Name - Link)</em><br />
<?php
echo '<ol>';
for($i = 0; $i < count($links[1]); $i++) {
echo '<li>' . $links[2][$i] . ' - ' . $links[1][$i] . '</li>';
}
echo '</ol>';
?>
</p>
有什么线索吗?
几个问题:
.
不匹配换行符,除非您在正则表达式末尾指定s
修饰符。所以应该加上。.*
是贪心的,所以会尽可能匹配包括一些中间的</p>
。它不应该那样做,所以添加一个?
(在这两种情况下)
问题不大,但仍然值得改变:
第一个捕获组可能没有给你有用的信息,所以去掉那里的括号。
.0001
中的.
被当作任意字符,所以要转义。一种方法是把它写成[.]
这给你这行代码:
preg_match_all('/<p class="MsoNormal" style="margin-bottom: [.]0001pt;.*?">(.*?)<\/p>/is',
$file_string, $links);
使用DOM解析器
请注意,如果您的来源 HTML 只是略有变化(额外的间距或将双引号更改为单引号,或交换属性的位置...),您将遇到问题,并被要求进行调整代码。
使用DOMDocument interface together with a DOMXPath query要好得多。这是它的工作原理:
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($file_string, LIBXML_NOCDATA | LIBXML_NOWARNING | LIBXML_NOERROR );
libxml_use_internal_errors(false);
$xpath = new DOMXPath($doc);
$nodes = $xpath->query("//p[contains(@class, 'MsoNormal') and contains(@style, 'margin-bottom: .0001pt')]");
foreach ($nodes as $node) {
echo $node->textContent . "\n";
}
您也可以使用 load
方法代替 loadHTML
方法,并将 URL 作为第一个参数传递。
跟进
您在评论中要求通过 tr
和 style
属性中的 mso-yfti-irow
进一步过滤输出:
$nodes = $xpath->query("//tr[contains(@style, 'mso-yfti-irow')]//p[contains(@class, 'MsoNormal') and contains(@style, 'margin-bottom: .0001pt')]");
正如其他人所说,请改用像样的解析器,例如DOMDocument()
:
<?php
# set up the dom
$dom = new DOMDocument();
$dom->loadHTML($your_data_here, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);# | LIBXML_COMPACT | LIBXML_NOENT );
# set up the xpath
$xpath = new DOMXPath($dom);
foreach ($xpath->query("//tr[contains(@style, 'mso-yfti-irow: 1')]") as $row) {
$text = $xpath->query("td/p/text()", $row);
$certificate = $text[0]->nodeValue;
$price = $text[1]->nodeValue;
echo "$certificate | $price\n";
}
?>
这会产生您的示例字符串:
Certifikat springer 1000m | 90,-
该代码片段设置了 DOM
并随后使用 xpath
表达式对其进行查询,请参阅 PHP.net
.