Im writing a program to pull the meta info from websites.
I need to write some regex to pull the text in the between the content tags.
$find = "<meta\s+name=['\"]??keywords['\"]??\s+content=['\"]??(.+)['\"]??\s*\/?>";
This works ok for meta keywords written like so:
<meta name="keywords" content="keyword, keyword, keyword" /> or like so
<meta name="keywords" content="keyword, keyword, keyword">
BuT I would like to flip it round so it can find the text inbetween the content tags in this format:
<meta content="keyword, keyword, keyword" name="keywords" /> or like so
<meta content="keyword, keyword, keyword" name="keywords" >
Anyone help? Cheers
For this purpose you could also use get_meta_tags() - a builtin PHP function which extracts <meta> tag attributes from websites (or already downloaded files):
$tags = get_meta_tags('http://www.example.com/');
print_r($tags);
Try this:
<meta[^>]*content="(?<keyword>[^"]*)"[^>]*/?>
Result:
You can also use PHP DOm
$doc=new DOMDocument();
$doc->loadHTML($htmlcontent);
$xpath= new DOMXPath($doc);
$nodelist=$xpath->query('//meta[#name='keywords']/#content');
foreach($nodelist as $node)
echo $node->nodeValue;
Using regexp works most of the time but it can not work safely on any HTML content.
Related
I have this data:
<meta name="description" content="Access Kenya is Kenya's leading corporate Internet service provider and is a technology solutions provider in Kenya with IT and network solutions for your business.Welcome to the Yellow Network.Kenya's leading Corporate and Residential ISP" />;
I am using this Regular Expression:
<meta +name *=[\"']?description[\"']? *content=[\"']?([^<>'\"]+)[\"']?
To get webpage description All works fine but everything stalls everywhere there is an apostrophe.
How do I escape that?
Your regular expression consider these three options for a <meta> node:
<meta name="description" content="Some Content" />
<meta name='description' content='Some Content' />
<meta name=description content=Some Content />
The third option is not valid HTML, but all can happen, so... you are right.
The simple way is to modify your original regular expression closing tag and using the ? not-greedy operator:
<meta +name *=[\"']?description[\"']? *content=[\"']?(.*?)[\"']? */?>
└─┘ └───┘
search zero-or-more characters except following closing tag characters
regex101 demo
But — also in this case — what happen if you have this meta?
<meta content="Some Content" name="description" />
Your regular expression will fail.
To real match a HTML node, you must use a parser:
$dom = new DOMDocument();
libxml_use_internal_errors(1);
$dom->loadHTML( $yourHtmlString );
$xpath = new DOMXPath( $dom );
$description = $xpath->query( '//meta[#name="description"]/#content' );
echo $description->item(0)->nodeValue);
will output:
Some Content
Yes, it's 5 lines vs 1, but with this method you will match any <meta name="description"> (also if it contains a third, not valid attribute).
Read more about DOMDocument
Read more about DOMXPath
Read why you can't parse [X]HTML with regular expressions
simple problem.
I have a site that uses meta tags. I want to extract the meta tags with PHP. However, when using "itemprop" in addition to "name" get_meta_tags() doesn't work.
<meta name="description" itemprop="description" content="Example content" />
Output of get_meta_tags()
false
<meta name="description" content="Example content" />
Output of get_meta_tags()
array (size=1)
'description' => string 'Example content' (length=157)
Do you have any idea why the itemprop addition makes such problems and if there's a method that can replace the get_meta_tags() or do I have to use sth. like phpQuery (since it's not recommended to use regex for html code)
It is not valid to have a name attribute and Microdata’s itemprop attribute on the same meta element.
So your HTML should look like:
<meta itemprop="description" content="Example content" />
<meta name="description" content="Example content" />
There are lots of answers to this question, but not a single complete one:
With using one regular expression, how do you extract page title from <title>Page title</title>?
There are several other cases how title tags are typed, such as:
<TITLE>Page title</TITLE>
<title>
Page title</title>
<title>
Page title
</title>
<title lang="en-US">Page title</title>
...or any combination of above.
And it can be on its own line or in between other tags:
<head>
<title>Page title</title>
</head>
<head><title>Page title</title></head>
Thanks for help in advance.
UDPATE: So, the regex approach might not be the best solution to this. Which PHP based HTML parser could handle all scenarios, where HTML is well formed (or not so well)?
UPDATE 2: sp00m's regex (https://stackoverflow.com/a/13510307/1844607) seems to be working in all cases. I'll get back to this if needed.
Use a HTML parser instead. But in case of:
<title[^>]*>(.*?)</title>
Demo
Use the DOMDocument class:
$doc = new DOMDocument();
$doc->loadHTML($html);
$titles = $doc->getElementsByTagName("title");
echo $titles->item[0]->nodeValue;
Use this regex:
<title>[\s\S]*?</title>
I was trying to change some parts of a joomla plugin, when I faced this part of it and I have no idea what it's doing.
Can someone please explain to me what these regular expressions and those ${4} do?
$comStart = '';
$comEnd = '';
$output = JResponse::getBody();
$output = preg_replace('/\<meta name=\"og\:/', '<meta property="og:', $output);
$output = preg_replace('/\<meta name=\"fb:admins/', '<meta property="fb:admins', $output);
$output = preg_replace('/<(\w+) (\w+)="(\w+):(\w+)" (\w+)="([a-zA-Z0-9\ \_\-\:\.\&\/\,\=\!\?]*)" \/>/i', $comStart.'<${1} ${2}="${3}:${4}" ${5}="${6}" >'.$comEnd, $output);
FYI: This plugin is for displaying facebook and opengraph tags inside articles.
SERIOUS NOTE!
The use of regular expressions to parse/match HTML/XML is highly
discouraged. Seriously, don't do it
Basically, it's a regular expression to parse/match HTML. Which may have slight side effects of not working, hard to maintain, and insanity.
The ${N} ones are called back-reference, they reference to the Nth brackets matched in the regular expressions.
If you require to do manipulation of HTML strings in PHP, you should use the DOMDocument class which was made exactly for this.
Example
<?php
$html_string = <<<HTML
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="target">
This is the target DIV! <span>This span will change texts!</span>
</div>
</body>
</html>
HTML;
$dom = new DOMDocument();
// Loading HTML from string...
$dom->loadHTML($html_string);
//Retrieve target and span elements
$target = $dom->getElementById("target");
$span = $target->getElementsByTagName("span")->item(0);
//Remove text, firstChild is the text node.
$span->removeChild($span->firstChild);
//Append new text
$span->appendChild(new DOMText("This is the new text!"));
//Change an attribute
$span->setAttribute("class", "spanny");
//Save HTML to string
$html_string = $dom->saveHTML();
echo $html_string;
Regular Expressions aren't bad, evil, or scary, they are simply the wrong tool for the job, you don't stick a nail with a jackhammer do you?
$output = preg_replace('/\<meta name=\"og\:/', '<meta property="og:', $output);
Replace the string <meta name="og: with <meta property="og:. Kind of pointless - regex is not needed here.
$output = preg_replace('/\<meta name=\"fb:admins/', '<meta property="fb:admins', $output);
Replace <meta name="fb:admins with <meta property="fb:admins. Just as pointless - regex is not needed here.
$output = preg_replace('/<(\w+) (\w+)="(\w+):(\w+)" (\w+)="([a-zA-Z0-9\ \_\-\:\.\&\/\,\=\!\?]*)" \/>/i', $comStart.'<${1} ${2}="${3}:${4}" ${5}="${6}" >'.$comEnd, $output);
Replace a string like <word1 word2="word3:word4" word5="word6withspecialcharacterslike-:.etc." /> with <word1 word2="word3:word4" word5=word6withspecialcharacterslike-:.etc." >. So it only removes a trailing slash before the closing >. Very suspect and Voodoo-like use of regex.
Also, all those regexes are highly inelegant (lots of pointless escapes, for example) and show that whoever wrote those doesn't know much about regexes. Letting something like this loose on HTML is asking for trouble.
AVOID! AVOID! AVOID!
Each (\w+) says find a word and store it. So you are doing this (in pseudocode)
find /(word1) (word2)="(word3)" (word4)="(manypossiblechars5)"/ignoring case
replace pattern with $comStart.<word1 word2="word3:word4" manypossiblechars5="word6">.$comEnd
The first one tries to replace tags of the form <meta name="og:... with <meta property="og:...
The second similarly replaces tags starting <meta name="fb:admins... with <meta property="fb:admins...
Finally, the third seems to take tags of the form <word word="word:word" word="something" \/> and wraps them with $comStart and $comEnd.
This is done by matching the parts of the tag (placing () around them) and then using backreferences such as ${4} to refer to the 4th matched part.
Here $comStart and $comEnd are set to '' so that seems a little pointless. It also manages to get rid of the closing slash for the tag at the same time, though who knows if that is intentional!
Those expressions attempt to fix the document head code by:
rewriting <meta name="og:*" to `
rewriting <meta name="fb:admins" to <meta property="fb:admins"
rewriting meta tags with a dangling slash to one without it (assuming it will always have two attributes.
This is just horrendous code, and as long as your templates don't have
those "mistakes" in them, you can throw this crap away.
How to get a html page source code without htl tags?
For example:
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="hu"/>
<title>this is the page title</title>
<meta name="description" content="this is the description" />
<meta name="keywords" content="k1, k2, k3, k4" />
start the body content
<!-- <div>this is comment</div> -->
open
End now one noframes tag.
<noframes><span>text</span></noframes>
<select name="select" id="select"><option>ttttt</option></select>
<div class="robots-nocontent"><span>something</span></div>
<img src="url.png" alt="this is alt attribute" />
I need this result:
this is the page title this is the description k1, k2, k3, k4 start the body content this is title attribute open End now one noframes tag. text ttttt something this is alt attribute
I need too the title and the alt attributes.
Idea?
You could do it with a regex.
$regex = '/\<.\>/';
would be a very simple start to remove anything with < and > around it. But in order to do this, you're going to have to pull in the HTML as a file_get_contents() or some other function that will turn the code into text.
Addendum:
If you want individual attributes pulled as well, you're going to have to write a more complex regex to pull that text out. For instance:
$regex2 = '/\<.(?<=(title))(\=\").(?=\")/';
Would pull out (I think... I'm still learning RegEx) any text between < and title=", assuming you had no other matching expressions before title. Again, this would be a pretty complicated regex process.
This cannot be done in an automated way. PHP cannot know which node attributes you want to omit. You'd either had to create some code that iterates over all attributes and textnodes which you can feed a map, defining when to use a node's content or you just pick what you want with XPath one by one.
An alternative would be to use XMLReader. It allows you to iterate over the entire document and define callbacks for the element names. This way, you can define what to do with what element. See
http://www.ibm.com/developerworks/library/x-pullparsingphp.html
My solution is a bit more complicate but it worked fine for me.
If you are sure that you have XHTML, you can simply consider the code as XML (but you have to put everything in a proper wrapping).
Then with XSLT you can define some basic templates that do what you need.