Я использую 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, но не смог найти достойных решений. Пожалуйста помоги.

Благодарность

3
ashutosh 19 Дек 2013 в 19:31

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;}

Вы получите следующие результаты, когда:

  1. Вы используете функцию 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
        )

    )
  1. Вы используете 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;
            )

    )
  1. Вы используете 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 ';' */

И он будет работать нормально.

Теперь вы можете вырезать любой результат, какой захотите. Вы можете вручную создать любую схему фильтра или настраиваемое регулярное выражение. Предложения приветствуются.

0
ashutosh 19 Дек 2013 в 20:15

Если вам нужны включенные css-файлы, просто найдите <link rel="stylesheet" src="source">, иначе вам придется искать встроенные style - элементы.

Что касается регулярных выражений, это был действительно полезный для меня сайт;)

RegExr

0
L00_Cyph3r 19 Дек 2013 в 15:42