PHP Conference Japan 2024

get_meta_tags

(PHP 4, PHP 5, PHP 7, PHP 8)

get_meta_tags从文件中提取所有 meta 标签 content 属性,返回一个数组

说明

get_meta_tags(string $filename, bool $use_include_path = false): array|false

打开 filename 文件,逐行解析文件中的 <meta> 标签。解析在 </head> 处停止。

参数

filename

HTML 文件的路径,字符串类型。可以是本地文件或 URL

示例 #1 get_meta_tags() 解析的内容

<meta name="author" content="name">
<meta name="keywords" content="php documentation">
<meta name="DESCRIPTION" content="a php manual">
<meta name="geo.position" content="49.33;-86.59">
</head> <!-- parsing stops here -->

use_include_path

use_include_path 设置为 true 将使 PHP 尝试根据 include_path 指令中的标准包含路径打开文件。此选项用于本地文件,而非 URL。

返回值

返回一个包含所有解析过的 meta 标签的数组。

name 属性的值作为键,content 属性的值作为返回数组的值,因此您可以轻松地使用标准数组函数遍历或访问单个值。name 属性值中的特殊字符将被替换为 '_',其余的转换为小写。如果两个 meta 标签具有相同的 name,则只返回最后一个。

失败时返回 false

范例

示例 #2 get_meta_tags() 的返回值

<?php
// 假设上述标签位于 www.example.com
$tags = get_meta_tags('http://www.example.com/');

// 注意键现在都是小写的,并且
// 键中的 . 被替换成了 _。
echo $tags['author']; // name
echo $tags['keywords']; // php documentation
echo $tags['description']; // a php manual
echo $tags['geo_position']; // 49.33;-86.59
?>

注释

Note:

只有具有 name 属性的 meta 标签才会被解析。不需要引号。

参见

添加注释

用户贡献的注释 19 条

up
53
bobble bubble
9 年前
此正则表达式通过捕获前瞻中的内容来获取 meta 标签,而不考虑顺序。
进一步使用分支重置功能来处理值的不同引号样式。
可以在此处测试该模式:https://regex101.com/r/oE4oU9/1

<?PHP

function getMetaTags($str)
{
$pattern = '
~<\s*meta\s

# 使用前瞻将类型捕获到 $1
(?=[^>]*?
\b(?:name|property|http-equiv)\s*=\s*
(?|"\s*([^"]*?)\s*"|\'\s*([^\']*?)\s*\'|
([^"\'>]*?)(?=\s*/?\s*>|\s\w+\s*=))
)

# 将 content 捕获到 $2
[^>]*?\bcontent\s*=\s*
(?|"\s*([^"]*?)\s*"|\'\s*([^\']*?)\s*\'|
([^"\'>]*?)(?=\s*/?\s*>|\s\w+\s*=))
[^>]*>

~ix'
;

if(
preg_match_all($pattern, $str, $out))
return
array_combine($out[1], $out[2]);
return array();
}

// 用法
$meta_tags = getMetaTags($str);

?>
up
3
jp at webgraphe dot com
20 年前
如果 URL 使用标头进行重定向(就像使用 PHP 函数 header("Location: URL"); 一样),则该页面通常没有内容。看起来 get_meta_tags() 不会捕获这种重定向(就像 cURL 会做的那样),这导致我的脚本超时。

我在编写的爬虫中遇到了这个问题,该爬虫用于将我网站上所有可用页面的信息提供给我的数据库,并且有一个链接链接到一个仅包含以下代码的页面

<?php
header
("Location: sections.php?section=home");
exit();
?>

这使我的脚本挂起了一会儿,显然,get_meta_tags() 甚至无法返回错误。

JP。
up
2
Ebpo
11 年前
请注意,该函数会在整个页面中查找元标记。如果出于某种原因在您的代码中注释了其中一个 meta,它仍然会被抓取。
up
6
richard dot dern at athaliasoft dot fr
11 年前
我个人在使用 DOM 函数而不是正则表达式尝试获取元标记而不使用 get_meta_tags 函数(为了也获取 http-equiv 元标记)时遇到的问题较少。

<?php

$doc
= new DOMDocument();
$doc->loadHTML($html);

$xpath = new DOMXPath($doc);

$nodes = $xpath->query('//head/meta');

foreach(
$nodes as $node) {
[...]
}

?>
up
2
匿名用户
22 年前
测试于 PHP 4.0.6

`get_meta_tags()` 函数似乎只在文件的开头查找,这意味着如果在 HTML 头部之前有大量的 PHP 代码,它将什么也不返回...
在 HTML 头部之前使用大约 9000 个字符的 PHP 代码对本地文件进行 `get_meta_tags()` 函数测试。

解决方法:如果可能,将代码移到头部之后,如果不行,则包含一个文件。
up
2
richard at pifmagazine dot com
24 年前
关于 META 标签和此函数的一个重要说明:如果你的 META 标签包含换行符 "\n",`get_meta_tags()` 函数将为该名称属性返回一个 NULL 值。从源 META 标签中删除换行符可以解决问题。
up
1
rehfeld
19 年前
回复
jp at webgraphe dot com

此函数抓取的是 meta 标签,而不是 http 头部

如果你需要头部信息

<?php

$fp
= fopen('http://example.org/somepage.html', 'r');

// 变量 $http_response_header 会神奇地出现
print_r($http_response_header);

// 或者
$meta_data = stream_get_meta_data($fp);
print_r($meta_data);

?>
up
5
mariano at cricava dot com
19 年前
基于 Michael Knapp 的代码,并添加了一些正则表达式,这里有一个函数可以根据 URL 获取所有 meta 标签和标题。如果有错误,它将返回 false。使用函数 `getUrlContents()`(也包含在内),它可以处理 META REFRESH 重定向,跟踪到指定数量的重定向。请注意,包含的正则表达式被分成字符串,因为 php.net 抱怨行太长了 ;)

<?php
function getUrlData($url)
{
$result = false;

$contents = getUrlContents($url);

if (isset(
$contents) && is_string($contents))
{
$title = null;
$metaTags = null;

preg_match('/<title>([^>]*)<\/title>/si', $contents, $match );

if (isset(
$match) && is_array($match) && count($match) > 0)
{
$title = strip_tags($match[1]);
}

preg_match_all('/<[\s]*meta[\s]*name="?' . '([^>"]*)"?[\s]*' . 'content="?([^>"]*)"?[\s]*[\/]?[\s]*>/si', $contents, $match);

if (isset(
$match) && is_array($match) && count($match) == 3)
{
$originals = $match[0];
$names = $match[1];
$values = $match[2];

if (
count($originals) == count($names) && count($names) == count($values))
{
$metaTags = array();

for (
$i=0, $limiti=count($names); $i < $limiti; $i++)
{
$metaTags[$names[$i]] = array (
'html' => htmlentities($originals[$i]),
'value' => $values[$i]
);
}
}
}

$result = array (
'title' => $title,
'metaTags' => $metaTags
);
}

return
$result;
}

function
getUrlContents($url, $maximumRedirections = null, $currentRedirection = 0)
{
$result = false;

$contents = @file_get_contents($url);

// 检查是否需要跳转到其他地方

if (isset($contents) && is_string($contents))
{
preg_match_all('/<[\s]*meta[\s]*http-equiv="?REFRESH"?' . '[\s]*content="?[0-9]*;[\s]*URL[\s]*=[\s]*([^>"]*)"?' . '[\s]*[\/]?[\s]*>/si', $contents, $match);

if (isset(
$match) && is_array($match) && count($match) == 2 && count($match[1]) == 1)
{
if (!isset(
$maximumRedirections) || $currentRedirection < $maximumRedirections)
{
return
getUrlContents($match[1][0], $maximumRedirections, ++$currentRedirection);
}

$result = false;
}
else
{
$result = $contents;
}
}

return
$contents;
}
?>

以下是其用法示例。检查包含的 URL 是否有 META REFRESH 重定向

<?php
$result
= getUrlData('http://www.marianoiglesias.com.ar/');

echo
'<pre>'; print_r($result); echo '</pre>';

?>

对于上面的代码,输出将是

<?php
Array
(
[
title] => 马里亚诺·伊格莱西亚斯永恒旅行者
[metaTags] => Array
(
[
description] => Array
(
[
html] => <meta name="description" content="Java、PHP 和一些其他的技术呓语。同时,也包括一些现实生活的内容。" />
[
value] => JavaPHP一些其他的技术呓语同时也包括一些现实生活内容
)

[
DC.title] => Array
(
[
html] => <meta name="DC.title" content="马里亚诺·伊格莱西亚斯 - 网络日志" />
[
value] => 马里亚诺·伊格莱西亚斯 - 网络日志
)

[
ICBM] => Array
(
[
html] => <meta name="ICBM" content="-34.6017, -58.3956" />
[
value] => -34.6017, -58.3956
)

[
geo.position] => Array
(
[
html] => <meta name="geo.position" content="-34.6017;-58.3956" />
[
value] => -34.6017;-58.3956
)

[
geo.region] => Array
(
[
html] => <meta name="geo.region" content="AR-BA">
[
value] => AR-BA
)

[
geo.placename] => Array
(
[
html] => <meta name="geo.placename" content="布宜诺斯艾利斯">
[
value] => 布宜诺斯艾利斯
)

)

)
?>
up
7
LWC
9 年前
基于 mariano at cricava dot com 的工作的新版本,包含:
1) 支持 Meta 属性(例如 Facebook 的 og 标签)。
2) 支持 Unicode (UTF-8) 编码的 Meta 行。
3) 一个不转换 HTML 实体的选项 - 如果您计划实际使用结果而不仅仅是显示它们。

function getUrlData($url, $raw=false) // $raw - 启用以进行原始显示
{
$result = false;

$contents = getUrlContents($url);

if (isset($contents) && is_string($contents))
{
$title = null;
$metaTags = null;
$metaProperties = null;

preg_match('/<title>([^>]*)<\/title>/si', $contents, $match );

if (isset($match) && is_array($match) && count($match) > 0)
{
$title = strip_tags($match[1]);
}

preg_match_all('/<[\s]*meta[\s]*(name|property)="?' . '([^>"]*)"?[\s]*' . 'content="?([^>"]*)"?[\s]*[\/]?[\s]*>/si', $contents, $match);

if (isset($match) && is_array($match) && count($match) == 4)
{
$originals = $match[0];
$names = $match[2];
$values = $match[3];

if (count($originals) == count($names) && count($names) == count($values))
{
$metaTags = array();
$metaProperties = $metaTags;
if ($raw) {
if (version_compare(PHP_VERSION, '5.4.0') == -1)
$flags = ENT_COMPAT;
else
$flags = ENT_COMPAT | ENT_HTML401;
}

for ($i=0, $limiti=count($names); $i < $limiti; $i++)
{
if ($match[1][$i] == 'name')
$meta_type = 'metaTags';
else
$meta_type = 'metaProperties';
if ($raw)
${$meta_type}[$names[$i]] = array (
'html' => htmlentities($originals[$i], $flags, 'UTF-8'),
'value' => $values[$i]
);
else
${$meta_type}[$names[$i]] = array (
'html' => $originals[$i],
'value' => $values[$i]
);
}
}
}

$result = array (
'title' => $title,
'metaTags' => $metaTags,
'metaProperties' => $metaProperties,
);
}

return $result;
}

function getUrlContents($url, $maximumRedirections = null, $currentRedirection = 0)
{
$result = false;

$contents = @file_get_contents($url);

// 检查是否需要跳转到其他地方

if (isset($contents) && is_string($contents))
{
preg_match_all('/<[\s]*meta[\s]*http-equiv="?REFRESH"?' . '[\s]*content="?[0-9]*;[\s]*URL[\s]*=[\s]*([^>"]*)"?' . '[\s]*[\/]?[\s]*>/si', $contents, $match);

if (isset($match) && is_array($match) && count($match) == 2 && count($match[1]) == 1)
{
if (!isset($maximumRedirections) || $currentRedirection < $maximumRedirections)
{
return getUrlContents($match[1][0], $maximumRedirections, ++$currentRedirection);
}

$result = false;
}
else
{
$result = $contents;
}
}

return $contents;
}
?>

<?php
$result
= getUrlData('http://whatever...', true);

echo
'<pre>'; print_r($result, true); echo '</pre>';

?>

输出示例

<?php
Array
(
[
title] => 请求页面的标题
[metaTags] => Array
(
[description] => Array
(
[html] => <meta name="description" content="一些内容..." />
[value] => 一些内容...
)
)
[metaProperties] => Array
(
[og:type] => Array
(
[html] => <meta property="og:type" content="article"/>/>
[value] => article
)
)
)
?>
up
4
roganty at gmail dot com
18 年前
这是对 jimmyxx at gmail dot com 函数的轻微修改

我尝试使用他代码中显示的正则表达式,但 PHP 抛出了几个错误

下面是有效的正确正则表达式
(请注意,我不得不将正则表达式拆分成字符串,因为 php.net 抱怨行太长)
<?php
preg_match_all
(
"|<meta[^>]+name=\"([^\"]*)\"[^>]" . "+content=\"([^\"]*)\"[^>]+>|i",
$html, $out,PREG_PATTERN_ORDER);
?>

问题是由于引号没有正确转义。
我希望这对遇到他的代码问题的人有所帮助
up
1
tim dot bennett at haveaniceplay dot com
19 年前
如果您想获取 meta 标签以外的其他标签的内容,您可以使用

<?php

$page
= "http://www.mysite.com/apage.php";

// 标签
$start = '<atag>';
$end = '<\/atag>';

// 打开文件
$fp = fopen( $page, 'r' );

$cont = "";

// 读取内容
while( !feof( $fp ) ) {
$buf = trim( fgets( $fp, 4096 ) );
$cont .= $buf;
}

// 获取标签内容
preg_match( "/$start(.*)$end/s", $cont, $match );

// 标签内容
$contents = $match[ 1 ];

?>
up
0
Michael Knapp
19 年前
Tim 的代码很好(谢谢 Tim),但如果标签是长的不间断字符串的一部分,它将无法很好地工作。

例如,尝试从谷歌地图获取标题 (http://www.google.com/maps)。

更好的解决方案是

<?php
$title
= "";

if (
$fp = @fopen( $_POST['url'], 'r' )) {

$cont = "";

// 读取内容
while( !feof( $fp ) ) {
$buf = trim(fgets( $fp, 4096 )) ;
$cont .= $buf;
}

// 获取标签内容
@preg_match( "/<title>([a-z 0-9]*)<\/title>/si", $cont, $match );

// 标签内容
$title = strip_tags(@$match[ 1 ]);
}

?>

注意 strip_tags。另一件需要注意的是检查 "、< 和 >。如果您要将输出发布到表单,则需要删除这些内容。

此外,最好使用 /i 修饰符,因为有些人可能会编写 <TITLE> 等...
up
0
richard 在 pifmagazine 点 com
24 年前
上面没有提到但应该提到的一点是:当对远程 PHP 页面使用 get_meta_tags 时,页面将在返回 meta 标签之前被解析 - 因此您可以捕获远程端(由 PHP?)动态生成的 meta 标签。

当获取本地文件系统上的 meta 标签时,这不会以相同的方式工作。本地文件在返回到 get_meta_tags() 之前不会通过 Web 服务器解析。如果 META 标签是硬编码到页面中的,您将一切正常 - 但如果是动态生成的,您将无法捕获它,除非您在调用本地文件时使用完整的 URL。
up
-2
doob_ 在 gmx 点 de
16 年前
<?php

/*
** 提取并格式化 meta 标签内容
*/

function get_meta_data($url, $searchkey='') {
$data = get_meta_tags($url); // 以数组形式获取 meta 数据
foreach($data as $key => $value) {
if(
mb_detect_encoding($value, 'UTF-8, ISO-8859-1', true) != 'ISO-8859-1') { // 检查内容是 UTF-8 还是 ISO-8859-1
$value = utf8_decode($value); // 如果是 UTF-8 则解码
}
$value = strtr($value, get_html_translation_table(HTML_ENTITIES)); // 对内容进行掩码处理
if($searchkey != '') { // 如果只需要一个 meta 标签,例如 'description'
if($key == $searchkey) {
$str = $value; // 只返回该值
}
} else {
// 所有 meta 标签
$pattern = '/ |,/i'; // ' ' 或 ','
$array = preg_split($pattern, $value, -1, PREG_SPLIT_NO_EMPTY); // 将其拆分为一个数组,这样我们就可以得到单词的数量
$str .= '<p><span style="display:block;color:#000000;font-weight:bold;">' . $key . ' <span style="font-weight:normal;">(' . count($array) . ' 个单词 | ' . strlen($value) . ' 个字符)</span></span>' . $value . '</p>'; // 格式化数据,包括单词和字符的数量
}
}
return
$str;
}

$content .= get_meta_data("http://www.example.com/");
/*
输出如下所示:

description (23 个单词 | 167 个字符)
SELFHTML 8.1.2 - HTML、JavaScript 和 CGI/Perl 的著名文档 - 教程和参考,以及关于设计、图形、项目管理等的大量额外提示。

keywords (13 个单词 | 119 个字符)
SELFHTML, HTML, Dynamic HTML, JavaScript, CGI, Perl, 图形, WWW 页面, 网页, 帮助, 文档, 描述

等等

*/

$content .= get_meta_data("http://www.example.com/", "description");
/*
输出如下所示:

SELFHTML 8.1.2 - HTML、JavaScript 和 CGI/Perl 的著名文档 - 教程和参考,以及关于设计、图形、项目管理等的大量额外提示。
*/

?>
up
-1
jstel 在 126 点 com
15 年前
此函数可以获取 HTML 内容的每个 meta 标签,并去除所有 js 和 css。

<?php
function get_meta_data($content)
{
$content = strtolower($content);
$content = preg_replace("'<style[^>]*>.*</style>'siU",'',$content); // 去除 js
$content = preg_replace("'<script[^>]*>.*</script>'siU",'',$content); // 去除 css
$split = explode("\n",$content);
foreach (
$split as $k => $v)
{
if (
strpos(' '.$v,'<meta')) {
preg_match_all(
"/<meta[^>]+(http\-equiv|name)=\"([^\"]*)\"[^>]" . "+content=\"([^\"]*)\"[^>]*>/i",
$v, $split_content[],PREG_PATTERN_ORDER);;
}
}
return
$split_content;
}
?>
up
-1
Ben 点 Davis 在 furman 点 edu
23 年前
我发现对于大型搜索,get_meta_tags 非常慢。我为一个无法使用数据库的网站创建了一个大型搜索引擎,我首先尝试提取 meta 标签。
我发现使用 eregi 提取 meta 标签实际上要快得多。下面的代码提取了 description:

if (eregi ("<meta name=\"description\" content=[^>]*", $contents, $descresult))
{
$description = explode("<meta name=\"description\" content=", $descresult[0]);
echo "<font face=\"Arial\" size=2>$description[1]</font>";

}
up
-2
Antonio - 马拉加
15 年前
如果 meta 语法没有尾部斜杠,则不起作用。
up
-3
diel 在 caroes 点 be
16 年前
快速 meta 数据抓取器
[代码]
if(get_meta_tags('http://'.$_POST['pagina'])){
print '<font class="midden">来自 http://'.$_POST['pagina'].' 的 Meta 数据</font>';
$metadata = get_meta_tags('http://'.$_POST['pagina']);
echo '<table width="100%">';
print '<tr><td>Meta</td><td>值</td></tr>';
foreach($metadata as $naam => $waarde){
echo '<tr><td valign="top">'.$naam.'</td><td>'.$waarde.'</td></tr>';
}
print '</table>';
}else{
print '
<div class="red_h">不正确</div>
';
}
[/代码]
up
-3
jimmyxx 在 gmail 点 com
19 年前
我将其用作我的迷你 PHP 搜索式搜索引擎的一部分 - 它确实拖慢了整个速度。我编写了这个函数来读取 HTML(只需获取文件或使用像 snoopy 这样的东西)并通过一个简单的正则表达式提取 meta 数据,效果很好,并使我的爬虫快得多。

<?php

function get_meta_data($html) {

preg_match_all(
"|<meta[^>]+name=\\"([^\\"]*)\\"[^>]+content=\\"([^\\"]*)\\"[^>]+>|i", $html, $out,PREG_PATTERN_ORDER);

for (
$i=0;$i < count($out[1]);$i++) {
// 遍历元数据 - 如果需要,您可以在此处添加自己的标签
if (strtolower($out[1][$i]) == "keywords") $meta['keywords'] = $out[2][$i];
if (
strtolower($out[1][$i]) == "description") $meta['description'] = $out[2][$i];
}

return
$meta;
}

?>
To Top