如何通过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 &#038; 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&amp;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 &#39;href&#39; contents of an &#39;a&#39; 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 &#39;href&#39; contents of an &#39;a&#39; 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】:

XMLish 更多的方式是使用 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 文档在 &lt;html&gt;-tag 中使用命名空间声明,则需要命名空间注册。

【讨论】:

用imdb.com/title/tt0120737 试试你的代码 ;-) 收到了很长的警告列表 没有必要在这里发起某种激烈的争吵......我实际上会选择preg_match-解决方案,但我只是想展示一种不同且更优雅的方法 - 不幸的是确实有一些现实世界中的问题(通常是由于使用了 HTML 实体或未转义的字符,如 &lt;&gt;&amp; 等) 那么,它与不可预知的结果相关联;因为在 html 网页中使用了广泛的命名空间。但我很欣赏你的思维方式! 你是对的。该方法更适合您了解文档的受控环境。命名空间问题可以通过检查声明的命名空间来解决,所以在我看来,更大的问题是大多数 HTML 文档远离标准。【参考方案8】:

使用原生 PHP 函数 get_meta_tags()。

https://php.net/get_meta_tags

【讨论】:

如问题中所述,“这仅适用于具有名称属性的元标记”,而 Open Graph 元标记没有,因此对于所需目的完全无用。

以上是关于如何通过php获取网页的开放图协议?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过chrome远程调试获取网页资源内容

如何获取网页的url

利用PHP从淘宝采集评论和成交数据

如何从GPS获取数据并发送到服务器以及如何保存到数据库

网页内如何调用开放的api接口实现用户定位

如何使用 PHP 实现网页交互