如何通过php获取网页的开放图协议?
Posted
技术标签:
【中文标题】如何通过php获取网页的开放图协议?【英文标题】:How to get Open Graph Protocol of a webpage by php? 【发布时间】:2011-11-19 06:11:32 【问题描述】:php 有一个简单的命令来获取网页的元标记 (get_meta_tags),但这仅适用于具有名称属性的元标记。然而,Open Graph 协议如今变得越来越流行。从网页获取 opg 值的最简单方法是什么。例如:
<meta property="og:url" content="">
<meta property="og:title" content="">
<meta property="og:description" content="">
<meta property="og:type" content="">
我看到的基本方法是通过 cURL 获取页面并使用正则表达式对其进行解析。有什么想法吗?
【问题讨论】:
【参考方案1】:真的很简单,做得很好:
使用https://github.com/scottmac/opengraph
$graph = OpenGraph::fetch('http://www.avessotv.com.br/bastidores-pantene-institute-experience-pg.html');
print_r($graph);
会回来
OpenGraph 对象
(
[_values:OpenGraph:private] => Array
(
[type] => article
[video] => http://www.avessotv.com.br/player/flowplayer/flowplayer-3.2.7.swf?config=%7B%27clip%27%3A%7B%27url%27%3A%27http%3A%2F%2Fwww.avessotv.com.br%2Fmedia%2Fprogramas%2Fpantene.flv%27%7D%7D
[image] => /wp-content/thumbnails/9025.jpg
[site_name] => Programa Avesso - Bastidores
[title] => Bastidores “Pantene Institute Experience†P&G
[url] => http://www.avessotv.com.br/bastidores-pantene-institute-experience-pg.html
[description] => Confira os bastidores do Pantene Institute Experience, da Procter & Gamble. www.pantene.com.br Mais imagens:
)
[_position:OpenGraph:private] => 0
)
【讨论】:
太棒了!!找了好几个小时,开箱即用! Github 用户 scottmac 似乎已经放弃了他的 OpenGraph 项目,但目前(2016 年初)有一个更新版本,有修复,这里:github.com/AramZS/opengraph 我喜欢这个包,但它不适用于重复的标签,我的意思是它获取最后一个重复的标签,例如 Youtube 正在重复标签(我不知道为什么):youtube.com/embed/C28onNQMXNU">...<metaproperty="og:video:url" content="youtube.com/v/C28onNQMXNU?version=3&autohide=1">,最后一个(也就是这个插件得到的那个)下载一个文件。糟透了 YouTube! 有谁知道为什么这不是从ajio.com/ajio-micro-print-spread-collar-shirt-/p/460292463_blue 等 URL 获取 og:site_name 吗?【参考方案2】:当从 HTML 解析数据时,你真的不应该使用正则表达式。看看DOMXPath Query function。
现在,实际的代码可能是:
[编辑] Stefan Gehrig 提供了更好的 XPath 查询,因此代码可以缩短为:
libxml_use_internal_errors(true); // Yeah if you are so worried about using @ with warnings
$doc = new DomDocument();
$doc->loadHTML($html);
$xpath = new DOMXPath($doc);
$query = '//*/meta[starts-with(@property, \'og:\')]';
$metas = $xpath->query($query);
$rmetas = array();
foreach ($metas as $meta)
$property = $meta->getAttribute('property');
$content = $meta->getAttribute('content');
$rmetas[$property] = $content;
var_dump($rmetas);
而不是:
$doc = new DomDocument();
@$doc->loadHTML($html);
$xpath = new DOMXPath($doc);
$query = '//*/meta';
$metas = $xpath->query($query);
$rmetas = array();
foreach ($metas as $meta)
$property = $meta->getAttribute('property');
$content = $meta->getAttribute('content');
if(!empty($property) && preg_match('#^og:#', $property))
$rmetas[$property] = $content;
var_dump($rmetas);
【讨论】:
老兄,我们生活在一个非想象的世界里,html 并不适合任何地方。在imdb.com/title/tt0120737 上检查您的代码@
不是解决方案。不要假装没有警告,而是编写一个不发出警告的代码
很好,这是您的解决方案,满意吗? :)
这是为了示例目的,但是现在我想应该没问题?
是的,libxml_use_internal_errors
-- 这是完美的解决方案,现在 +1 ;-)【参考方案3】:
怎么样:
preg_match_all('~<\s*meta\s+property="(og:[^"]+)"\s+content="([^"]*)~i', $str, $matches);
所以,是的,以任何方式抓取页面并使用正则表达式进行解析
【讨论】:
谢谢,但我希望能找到 preg_match 以外的方法 :) @zerkms 在解析 HTML 时,它比 DomDocument 脏、不可靠且效率低。 @Thomas Cantonnet:效率低下??preg_replace
在 imdb.com/title/tt0120737 上的速度比您的解决方案快约 100 倍,而且它不会引发任何警告,哈哈?
@zerkms 好吧,试试你的代码: 有用吗?不。 有用吗?没有。
大家好,从某种意义上说,你们俩都是对的。 preg_match 快速但不可靠。 DOM 是可靠的,但速度很慢,而且消耗资源。我个人更喜欢 preg_match 但结构上的微小变化可能会毁掉你的整个世界。【参考方案4】:
此函数无需依赖和 DOM 解析即可完成工作:
function getOgTags($html)
$pattern='/<\s*meta\s+property="og:([^"]+)"\s+content="([^"]*)/i';
if(preg_match_all($pattern, $html, $out))
return array_combine($out[1], $out[2]);
return array();
测试代码:
$x=' <title>php - Using domDocument, and parsing info, I would like to get the 'href' contents of an 'a' tag - Stack Overflow</title>
<link rel="shortcut icon" href="https://cdn.sstatic.net/Sites/***/img/favicon.ico?v=4f32ecc8f43d">
<link rel="apple-touch-icon image_src" href="https://cdn.sstatic.net/Sites/***/img/apple-touch-icon.png?v=c78bd457575a">
<link rel="search" type="application/opensearchdescription+xml" title="Stack Overflow" href="/opensearch.xml">
<meta name="referrer" content="origin" />
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://***.com/questions/5278418/using-domdocument-and-parsing-info-i-would-like-to-get-the-href-contents-of"/>
<meta property="og:image" itemprop="image primaryImageOfPage" content="https://cdn.sstatic.net/Sites/***/img/apple-touch-icon@2.png?v=73d79a89bded" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:domain" content="***.com"/>
<meta name="twitter:title" property="og:title" itemprop="title name" content="Using domDocument, and parsing info, I would like to get the 'href' contents of an 'a' tag" />
<meta name="twitter:description" property="og:description" itemprop="description" content="Possible Duplicate:
Regular expression for grabbing the href attribute of an A element
This displays the what is between the a tag, but I would like a way to get the href contents as well.
Is..." />';
echo '<pre>';
var_dump(getOgTags($x));
你会得到:
array(3)
["type"]=>
string(7) "website"
["url"]=>
string(119) "https://***.com/questions/5278418/using-domdocument-and-parsing-info-i-would-like-to-get-the-href-contents-of"
["image"]=>
string(85) "https://cdn.sstatic.net/Sites/***/img/apple-touch-icon@2.png?v=73d79a89bded"
【讨论】:
【参考方案5】:按照此方法,您将获得 fabcebook 开放图形标签的密钥对数组。
$url="http://fbcpictures.in";
$site_html= file_get_contents($url);
$matches=null;
preg_match_all('~<\s*meta\s+property="(og:[^"]+)"\s+content="([^"]*)~i', $site_html,$matches);
$ogtags=array();
for($i=0;$i<count($matches[1]);$i++)
$ogtags[$matches[1][$i]]=$matches[2][$i];
【讨论】:
【参考方案6】:这是我用来提取 Og 标签的。
function get_og_tags($get_url = "", $ret = 0)
if ($get_url != "")
$title = "";
$description = "";
$keywords = "";
$og_title = "";
$og_image = "";
$og_url = "";
$og_description = "";
$full_link = "";
$image_urls = array();
$og_video_name = "";
$youtube_video_url="";
$get_url = $get_url;
$ret_data = file_get_contents_curl($get_url);
//$html = file_get_contents($get_url);
$html = $ret_data['curlData'];
$full_link = $ret_data['full_link'];
$full_link = addhttp($full_link);
//parsing begins here:
$doc = new DOMDocument();
@$doc->loadHTML($html);
$nodes = $doc->getElementsByTagName('title');
if ($nodes->length == 0)
$title = $get_url;
else
$title = $nodes->item(0)->nodeValue;
//get and display what you need:
$metas = $doc->getElementsByTagName('meta');
for ($i = 0; $i < $metas->length; $i++)
$meta = $metas->item($i);
if ($meta->getAttribute('name') == 'description')
$description = $meta->getAttribute('content');
if ($meta->getAttribute('name') == 'keywords')
$keywords = $meta->getAttribute('content');
$og = $doc->getElementsByTagName('og');
for ($i = 0; $i < $metas->length; $i++)
$meta = $metas->item($i);
if ($meta->getAttribute('property') == 'og:title')
$og_title = $meta->getAttribute('content');
if ($meta->getAttribute('property') == 'og:url')
$og_url = $meta->getAttribute('content');
if ($meta->getAttribute('property') == 'og:image')
$og_image = $meta->getAttribute('content');
if ($meta->getAttribute('property') == 'og:description')
$og_description = $meta->getAttribute('content');
// for sociotube video share
if ($meta->getAttribute('property') == 'og:video_name')
$og_video_name = $meta->getAttribute('content');
// for sociotube youtube video share
if ($meta->getAttribute('property') == 'og:youtube_video_url')
$youtube_video_url = $meta->getAttribute('content');
//if no image found grab images from body
if ($og_image != "")
$image_urls[] = $og_image;
else
$xpath = new DOMXPath($doc);
$nodelist = $xpath->query("//img"); // find your image
$imgCount = 0;
for ($i = 0; $i < $nodelist->length; $i++)
$node = $nodelist->item($i); // gets the 1st image
if (isset($node->attributes->getNamedItem('src')->nodeValue))
$src = $node->attributes->getNamedItem('src')->nodeValue;
if (isset($node->attributes->getNamedItem('src')->value))
$src = $node->attributes->getNamedItem('src')->value;
if (isset($src))
if (!preg_match('/blank.(.*)/i', $src) && filter_var($src, FILTER_VALIDATE_URL))
$image_urls[] = $src;
if ($imgCount == 10) break;
$imgCount++;
$page_title = ($og_title == "") ? $title : $og_title;
if(!empty($og_video_name))
// for sociotube video share
$page_body = $og_video_name;
else
// for post share
$page_body = ($og_description == "") ? $description : $og_description;
$output = array('title' => $page_title, 'images' => $image_urls, 'content' => $page_body, 'link' => $full_link,'video_name'=>$og_video_name,'youtube_video_url'=>$youtube_video_url);
if ($ret == 1)
return $output; //output JSON data
echo json_encode($output); //output JSON data
die;
else
$data = array('error' => "Url not found");
if ($ret == 1)
return $data; //output JSON data
echo json_encode($data);
die;
函数的使用
$url = "https://www.alectronics.com";
$tagsArray = get_og_tags($url);
print_r($tagsArray);
【讨论】:
【参考方案7】:XML
ish 更多的方式是使用 XPath:
$xml = simplexml_load_file('http://ogp.me/');
$xml->registerXPathNamespace('h', 'http://www.w3.org/1999/xhtml');
$result = array();
foreach ($xml->xpath('//h:meta[starts-with(@property, \'og:\')]') as $meta)
$result[(string)$meta['property']] = (string)$meta['content'];
print_r($result);
不幸的是,如果 HTML 文档在 <html>
-tag 中使用命名空间声明,则需要命名空间注册。
【讨论】:
用imdb.com/title/tt0120737 试试你的代码 ;-) 收到了很长的警告列表 没有必要在这里发起某种激烈的争吵......我实际上会选择preg_match
-解决方案,但我只是想展示一种不同且更优雅的方法 - 不幸的是确实有一些现实世界中的问题(通常是由于使用了 HTML 实体或未转义的字符,如 <
、>
、&
等)
那么,它与不可预知的结果相关联;因为在 html 网页中使用了广泛的命名空间。但我很欣赏你的思维方式!
你是对的。该方法更适合您了解文档的受控环境。命名空间问题可以通过检查声明的命名空间来解决,所以在我看来,更大的问题是大多数 HTML 文档远离标准。【参考方案8】:
使用原生 PHP 函数 get_meta_tags()。
https://php.net/get_meta_tags
【讨论】:
如问题中所述,“这仅适用于具有名称属性的元标记”,而 Open Graph 元标记没有,因此对于所需目的完全无用。以上是关于如何通过php获取网页的开放图协议?的主要内容,如果未能解决你的问题,请参考以下文章