DOM 中的空属性 returns 意外的回退值
An empty attribute in DOM returns an unexpected fallback value
我已经检索到此网页的内容 http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369
并将其保存到 $webpage
。
请注意:
在此网页中,有多个 <meta>
标签。其中一个 meta-tags 是罪魁祸首,并导致了一些问题。这个meta-tag就是<meta property="og:description" content="" />
。请注意,content
的值是一个空字符串。
我正在阅读网页内容如下:
<?php
$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369';
$webpage = file_get_contents($url);
$og_entry_title = "";
$og_entry_content = "";
$doc = new DOMDocument;
$doc->loadHTML($webpage);
$meta_tags = $doc->getElementsByTagName('meta');
foreach ($meta_tags as $meta_tag) {
if ($meta_tag->getAttribute('property') == 'og:title') {
$og_entry_title = $meta_tag->getAttribute('content');
}
if ($meta_tag->getAttribute('property') == 'og:description') {
$og_entry_content = $meta_tag->getAttribute('content');
}
}
// print the results
echo
'$og_entry_title: ' . $og_entry_title
.PHP_EOL.
'$og_entry_content: ' . $og_entry_content;
完成后,$og_entry_title
和 $og_entry_content
的值如下:
$og_entry_title: TOP STORIES | DW.COM
$og_entry_content: News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment.
请注意结果中的以下内容:
$og_entry_title
正确并包含页面标题,所以这里没有问题
$og_entry_content
给出了与我预期不同的值。我希望在 $og_entry_content
中保存一个空字符串;但是字符串 "News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment." 被保存了。该字符串似乎是元标记包含空字符串时返回的后备值(或默认值)。
经过进一步调查,发现 go:description
是从 http://www.dw.com
网页获取其 meta-tag 值。发生这种情况似乎是因为我的网页包含一个空字符串,返回值是从站点的根页面检索的。
我有以下关于 $og_entry_content
的问题:
如何确保将空字符串(不是回退值)保存到$og_entry_content
?
为什么返回根页面的回退值?
谢谢。
回答
您的网址中包含需要 URL encoded.
的特殊字符
说明
首先,假设...
$og_entry_title
is correct and contains the page title, so no problem here
...错了。
这个标题:
<meta property="og:title" content="تقرير استخباري اميركي: القاعدة تسيطر على غرب العراق | أخبار | DW.COM | 28.11.2006" />
与此标题不一样:
<meta property="og:title" content="TOP STORIES | DW.COM" />
其次,大多数现代浏览器都非常强大,可以即时进行 URL 编码,并且仍会在地址栏中显示特殊字符。
您可以 see the response headers 从网络服务器获取更多信息。
<?php
$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$url");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$response = curl_exec($ch);
// Then, after your curl_exec call:
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
echo '
header
------
'.substr($response, 0, $header_size);
结果显示它无法识别 URL 与该页面之间的关联:
header
------
HTTP/1.1 301 Moved Permanently
Server: Apache-Coyote/1.1
Location: /
Content-Length: 0
Accept-Ranges: bytes
X-Varnish: 99639238
Date: Thu, 16 Jun 2016 15:42:51 GMT
Connection: keep-alive
HTTP Response Code 301
是一个通知(永久)重定向到另一个页面。 Location: /
表示您应该直接转到 主页 。这是一种常见的草率做法,当某人不知道如何处理您时就将其发送到主页。
默认情况下,Curl 不会遵循重定向,这就是我们能够检查 301 响应的方式 header。但是 file_get_contents
将遵循重定向,这就是为什么您得到的内容与您预期的不同。 (可能有例外:有一个 bug report,有些人注意到它并不总是遵循重定向。)
请注意主页 在其 og:description
中有 content
:
<?php
echo file_get_contents('http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369');
此输出结果:
...
<meta property="og:description" content="News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment. " />
...
<meta property="og:title" content="TOP STORIES | DW.COM" />
...
解决方案
您需要做的第一件事是 rawurlencode
网址:
$url = rawurlencode($url);
然后意识到 rawurlencode
命名不当,因为 valid URL 将包含 HTML 协议 http://
或 https://
并且还可能包含斜线来分隔部分。这是有问题的,因为 rawurlencode
会将冒号 :
转换为 %3A
并将斜线 /
转换为 %2F
这会导致无效的 URL ,例如 http%3A%2F%2Fwww.dw.com%2Far%2F...
.它应该被命名为 rawurlencode_parts_of_URL
,但他们没有问我 :) 在他们的辩护中引用 Phil Karlton 的话:
There are only two hard things in Computer Science: cache invalidation and naming things.
因此将斜杠和冒号转换回原来的形式:
$url = str_replace('%3A',':',str_replace('%2F','/',$url));
最后,你需要做的最后一件事是send a header to your clients to let them know what kind of font encoding to expect。
header("content-type: text/html; charset=utf-8");
否则,您的客户可能正在阅读一些 gobbledygook 看起来像这样的内容:
تقرير استخباري اميركي: القاعدة تسيطر على غرب العراÙ
最终产品
<?php
// let's see error output on screen while in development
// remove these lines for production, and use log files only
error_reporting(-1);
ini_set('display_errors', 'On');
$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369';
// URL encode special chars
$url = rawurlencode($url);
// fix colons and slashses for valid URL
$url = str_replace('%3A',':',str_replace('%2F','/',$url));
// make request
$webpage = file_get_contents($url);
$og_entry_title = "";
$og_entry_content = "";
$doc = new DOMDocument;
$doc->loadHTML($webpage);
$meta_tags = $doc->getElementsByTagName('meta');
foreach ($meta_tags as $meta_tag) {
if ($meta_tag->getAttribute('property') == 'og:title') {
$og_entry_title = $meta_tag->getAttribute('content');
}
if ($meta_tag->getAttribute('property') == 'og:description') {
$og_entry_content = $meta_tag->getAttribute('content');
}
}
// set the character set for the client
header("content-type: text/html; charset=utf-8");
// print the results
echo
'$og_entry_title: ' . $og_entry_title
.PHP_EOL.
'$og_entry_content: ' . $og_entry_content;
此输出结果:
$og_entry_title: تقرير استخباري اميركي: القاعدة تسيطر على غرب العراق | أخبار | DW.COM | 28.11.2006
$og_entry_content:
附录
如果您正在查看您的 error logs,并且您确实 应该 总是 在以下时间查看您的错误日志开发,然后你会注意到一连串的警告:
Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 4 in ...
Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 5 in ...
Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 6 in ...
Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 7 in ...
Warning: DOMDocument::loadHTML(): ID topMetaInner already defined in Entity, line: 300 in ...
Warning: DOMDocument::loadHTML(): ID langSelectTrigger already defined in Entity, line: 315 in ...
Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 546 in ...
Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 546 in ...
Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 548 in ...
Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 548 in ...
这是因为您正试图将 DOMDocument class 与 in-valid HTML and not well-formed XML documents 一起使用。但这是另一个问题的主题。
我已经检索到此网页的内容 http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369
并将其保存到 $webpage
。
请注意:
在此网页中,有多个 <meta>
标签。其中一个 meta-tags 是罪魁祸首,并导致了一些问题。这个meta-tag就是<meta property="og:description" content="" />
。请注意,content
的值是一个空字符串。
我正在阅读网页内容如下:
<?php
$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369';
$webpage = file_get_contents($url);
$og_entry_title = "";
$og_entry_content = "";
$doc = new DOMDocument;
$doc->loadHTML($webpage);
$meta_tags = $doc->getElementsByTagName('meta');
foreach ($meta_tags as $meta_tag) {
if ($meta_tag->getAttribute('property') == 'og:title') {
$og_entry_title = $meta_tag->getAttribute('content');
}
if ($meta_tag->getAttribute('property') == 'og:description') {
$og_entry_content = $meta_tag->getAttribute('content');
}
}
// print the results
echo
'$og_entry_title: ' . $og_entry_title
.PHP_EOL.
'$og_entry_content: ' . $og_entry_content;
完成后,$og_entry_title
和 $og_entry_content
的值如下:
$og_entry_title: TOP STORIES | DW.COM $og_entry_content: News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment.
请注意结果中的以下内容:
$og_entry_title
正确并包含页面标题,所以这里没有问题
$og_entry_content
给出了与我预期不同的值。我希望在 $og_entry_content
中保存一个空字符串;但是字符串 "News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment." 被保存了。该字符串似乎是元标记包含空字符串时返回的后备值(或默认值)。
经过进一步调查,发现 go:description
是从 http://www.dw.com
网页获取其 meta-tag 值。发生这种情况似乎是因为我的网页包含一个空字符串,返回值是从站点的根页面检索的。
我有以下关于 $og_entry_content
的问题:
如何确保将空字符串(不是回退值)保存到
$og_entry_content
?为什么返回根页面的回退值?
谢谢。
回答
您的网址中包含需要 URL encoded.
的特殊字符说明
首先,假设...
$og_entry_title
is correct and contains the page title, so no problem here
...错了。
这个标题:
<meta property="og:title" content="تقرير استخباري اميركي: القاعدة تسيطر على غرب العراق | أخبار | DW.COM | 28.11.2006" />
与此标题不一样:
<meta property="og:title" content="TOP STORIES | DW.COM" />
其次,大多数现代浏览器都非常强大,可以即时进行 URL 编码,并且仍会在地址栏中显示特殊字符。
您可以 see the response headers 从网络服务器获取更多信息。
<?php
$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$url");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$response = curl_exec($ch);
// Then, after your curl_exec call:
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
echo '
header
------
'.substr($response, 0, $header_size);
结果显示它无法识别 URL 与该页面之间的关联:
header ------ HTTP/1.1 301 Moved Permanently Server: Apache-Coyote/1.1 Location: / Content-Length: 0 Accept-Ranges: bytes X-Varnish: 99639238 Date: Thu, 16 Jun 2016 15:42:51 GMT Connection: keep-alive
HTTP Response Code 301
是一个通知(永久)重定向到另一个页面。 Location: /
表示您应该直接转到 主页 。这是一种常见的草率做法,当某人不知道如何处理您时就将其发送到主页。
默认情况下,Curl 不会遵循重定向,这就是我们能够检查 301 响应的方式 header。但是 file_get_contents
将遵循重定向,这就是为什么您得到的内容与您预期的不同。 (可能有例外:有一个 bug report,有些人注意到它并不总是遵循重定向。)
请注意主页 在其 og:description
中有 content
:
<?php
echo file_get_contents('http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369');
此输出结果:
...
<meta property="og:description" content="News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment. " />
...
<meta property="og:title" content="TOP STORIES | DW.COM" />
...
解决方案
您需要做的第一件事是 rawurlencode
网址:
$url = rawurlencode($url);
然后意识到 rawurlencode
命名不当,因为 valid URL 将包含 HTML 协议 http://
或 https://
并且还可能包含斜线来分隔部分。这是有问题的,因为 rawurlencode
会将冒号 :
转换为 %3A
并将斜线 /
转换为 %2F
这会导致无效的 URL ,例如 http%3A%2F%2Fwww.dw.com%2Far%2F...
.它应该被命名为 rawurlencode_parts_of_URL
,但他们没有问我 :) 在他们的辩护中引用 Phil Karlton 的话:
There are only two hard things in Computer Science: cache invalidation and naming things.
因此将斜杠和冒号转换回原来的形式:
$url = str_replace('%3A',':',str_replace('%2F','/',$url));
最后,你需要做的最后一件事是send a header to your clients to let them know what kind of font encoding to expect。
header("content-type: text/html; charset=utf-8");
否则,您的客户可能正在阅读一些 gobbledygook 看起来像这样的内容:
تقرير استخباري اميركي: القاعدة تسيطر على غرب العراÙ
最终产品
<?php
// let's see error output on screen while in development
// remove these lines for production, and use log files only
error_reporting(-1);
ini_set('display_errors', 'On');
$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369';
// URL encode special chars
$url = rawurlencode($url);
// fix colons and slashses for valid URL
$url = str_replace('%3A',':',str_replace('%2F','/',$url));
// make request
$webpage = file_get_contents($url);
$og_entry_title = "";
$og_entry_content = "";
$doc = new DOMDocument;
$doc->loadHTML($webpage);
$meta_tags = $doc->getElementsByTagName('meta');
foreach ($meta_tags as $meta_tag) {
if ($meta_tag->getAttribute('property') == 'og:title') {
$og_entry_title = $meta_tag->getAttribute('content');
}
if ($meta_tag->getAttribute('property') == 'og:description') {
$og_entry_content = $meta_tag->getAttribute('content');
}
}
// set the character set for the client
header("content-type: text/html; charset=utf-8");
// print the results
echo
'$og_entry_title: ' . $og_entry_title
.PHP_EOL.
'$og_entry_content: ' . $og_entry_content;
此输出结果:
$og_entry_title: تقرير استخباري اميركي: القاعدة تسيطر على غرب العراق | أخبار | DW.COM | 28.11.2006 $og_entry_content:
附录
如果您正在查看您的 error logs,并且您确实 应该 总是 在以下时间查看您的错误日志开发,然后你会注意到一连串的警告:
Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 4 in ... Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 5 in ... Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 6 in ... Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 7 in ... Warning: DOMDocument::loadHTML(): ID topMetaInner already defined in Entity, line: 300 in ... Warning: DOMDocument::loadHTML(): ID langSelectTrigger already defined in Entity, line: 315 in ... Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 546 in ... Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 546 in ... Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 548 in ... Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 548 in ...
这是因为您正试图将 DOMDocument class 与 in-valid HTML and not well-formed XML documents 一起使用。但这是另一个问题的主题。