Я использую Simple Html Dom для получения HTML-структуры веб-страницы. Я также получаю весь внешний CSS, который использует страница. Вот код:
Class MyClass {
//... Rest of irrelevant code
private function get_web_page($url)
{
$user_agent='Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0';
$options = array(
CURLOPT_CUSTOMREQUEST => "POST", //set request type post or get
CURLOPT_POST => true, //set to POST
CURLOPT_POSTFIELDS => array(),
CURLOPT_USERAGENT => $user_agent, //set user agent
CURLOPT_COOKIEFILE => "cookie.txt", //set cookie file
CURLOPT_COOKIEJAR => "cookie.txt", //set cookie jar
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_BINARYTRANSFER => true,
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );
$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}
private function collect_css($url,$html)
{
$css = array();
foreach($html->find('link') as $e){
$css[] = file_get_contents($e,true); //Consider all as absolute URL
}
return $css;
}
private function collect_inlinecss($url,$html)
{
$css = array();
foreach($html->find('style') as $e){
$css = $e->innertext //Get inline CSS
}
return $css;
}
private function filter_css($css)
{
/* What should I place here to get only certain attributes (for ex- 'display' attribute only for this case)
* For example- if $css = #selector{ display : block; color: blue },
* the function should return only $css = #selector{ display : block; }
*/
}
public function index(){
$url = "http://www.example.com";
$raw = $this->get_web_page($url);
$html = str_get_html($raw['content']); //Get only HTML content using Simple HTML Dom Lib
$css = $this->collect_css($url,$html); //Get all external CSS files of webpage
$css_inline = $this->collect_inlinecss($url,$html); //Get inline CSS (<style>....</style>)
$css_filtered = $this->filter_css($css);
var_dump($css_filtered); //See next for how I want it to look like
}
var_dump
должен содержать обрезанный Css. Желаемый результат для примера ввода Css должен выглядеть так:
Input CSS(the input for filter function):
#id{
display: block;
color: blue;
padding: 0 5px;
}
#id2{
background: Yellow;
margin: 0px;
position: relative;
}
#id3{ float: left; }
Output Css (the expected result from var_dump):
/* I wish to strip off every style except 'display' and 'position' */
#id{
display: block;
}
#id2{
position: relative;
}
Может ли кто-нибудь просветить меня каким-нибудь лучиком надежды или еще чем-нибудь. Я знаю, что регулярное выражение может немного помочь, хотя я в этом не разбираюсь и не знаю хороших плагинов. PS: Те, кто здесь, чтобы сказать, что я не гуглил, прежде чем спросил - я потратил 1 час, чтобы бросить вопросы вроде this, this, но не смог найти достойных решений. Пожалуйста помоги.
Благодарность
2 ответа
Большое спасибо @Pete за отличную ссылку, которой он поделился. Следующие фрагменты кода решили мои проблемы. Вы можете выбрать любое регулярное выражение / функцию.
private function parse_css($css)
{
$css_array = array(); // master array to hold all values
$element = explode('}', $css);
foreach ($element as $element) {
// get the name of the CSS element
$a_name = explode('{', $element);
$name = $a_name[0];
// get all the key:value pair styles
$a_styles = explode(';', $element);
// remove element name from first property element
$a_styles[0] = str_replace($name . '{', '', $a_styles[0]);
// loop through each style and split apart the key from the value
$count = count($a_styles);
for ($a=0;$a<$count;$a++) {
if ($a_styles[$a] != '') {
$a_key_value = explode(':', $a_styles[$a]);
// build the master css array
$css_array[$name][$a_key_value[0]] = $a_key_value[1];
}
}
}
return $css_array;
}
private function filter_css($css)
{
//$regex1 = '/([^{]+)\s*\{\s*([^}]+)\s*}/';
//$regex2 = '/(?<selector>(?:(?:[^,{]+),?)*?)\{(?:(?<name>[^}:]+):?(?<value>[^};]+);?)*?\}/';
$newcss = $this->parse_css($css); //One way
//preg_match_all('regex1',$css,$newcss); //another way
//preg_match_all('regex2',$css,$newcss); //yet another way
return $newcss;
}
Вышеупомянутая функция использует в основном 2 регулярных выражения и 1 функцию для синтаксического анализа CSS, что делает доступными для использования всего 3 метода. У каждого метода разные порядки вывода.
Например, рассмотрим следующий файл CSS:
#id{ display: block; color: blue; padding: 0 5px;}
#id2{ background: Yellow; margin: 0px; position: relative;}
#id3{ float: left;}
Вы получите следующие результаты, когда:
- Вы используете функцию
parse_css
:
#output: Array ( [#id] => Array ( [ display] => block [ color] => blue [ padding] => 0 5px ) [#id2] => Array ( [ background] => Yellow [ margin] => 0px [ position] => relative ) [#id3] => Array ( [ float] => left ) )
- Вы используете
regex1
:
#output: Array ( [0] => Array ( [0] => #id{ display: block; color: blue; padding: 0 5px;} [1] => #id2{ background: Yellow; margin: 0px; position: relative;} [2] => #id3{ float: left;} ) [1] => Array ( [0] => #id [1] => #id2 [2] => #id3 ) [2] => Array ( [0] => display: block; color: blue; padding: 0 5px; [1] => background: Yellow; margin: 0px; position: relative; [2] => float: left; ) )
- Вы используете
regex2
:
#output: Array ( [0] => Array ( [0] => #id{ display: block; color: blue; padding: 0 5px;} [1] => #id2{ background: Yellow; margin: 0px; position: relative;} [2] => #id3{ float: left;} ) [selector] => Array ( [0] => #id [1] => #id2 [2] => #id3 ) [1] => Array ( [0] => #id [1] => #id2 [2] => #id3 ) [name] => Array ( [0] => padding [1] => position [2] => float ) [2] => Array ( [0] => padding [1] => position [2] => float ) [value] => Array ( [0] => 0 5px [1] => relative [2] => left ) [3] => Array ( [0] => 0 5px [1] => relative [2] => left ) )
Вы можете видеть, что regex2
дает вам больше гибкости и возможностей, чем другие. Я бы также лично не рекомендовал использовать функцию parse_css
, потому что в ней есть ошибка, которая пропускает ошибку, если в вашем CSS закрывающие фигурные скобки содержат пробелы. Например, если ваш CSS:
#ie{ display:block; } /* notice the space after ';' */
Это даст вам следующую ошибку: Notice: Undefined offset: 1 in path/to/your/file.php on line xx
Но работает нормально, если нет пробелов. Например, когда приведенный выше CSS записан как:
#ie{ display:block;} /* notice no space after ';' */
И он будет работать нормально.
Теперь вы можете вырезать любой результат, какой захотите. Вы можете вручную создать любую схему фильтра или настраиваемое регулярное выражение. Предложения приветствуются.
Если вам нужны включенные css-файлы, просто найдите <link rel="stylesheet" src="source">
, иначе вам придется искать встроенные style
- элементы.
Что касается регулярных выражений, это был действительно полезный для меня сайт;)
Похожие вопросы
Связанные вопросы
Новые вопросы
php
PHP - это широко используемый высокоуровневый, динамический, объектно-ориентированный и интерпретируемый язык сценариев, в первую очередь предназначенный для серверной веб-разработки. Используется для вопросов о языке PHP.