Извлечение URL-адреса изображения в HTML с помощью регулярного выражения (regex)


Оказывается, я пытаюсь извлечь изображение следующим образом:

$url = 'https://m.fa.com/perfil123';//cualquier perfil
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url );
curl_setopt($ch,CURLOPT_HEADER,0); //visualizar ñ y acentos.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt($ch, CURLOPT_ENCODING, "gzip,deflate"); //(aceptación de codificación gzip)   
$url = curl_exec($ch); //almacena el response de la pagina.

curl_close($ch);
    preg_match('#class="bo img" src=[^"]*"([^"]*)"#', $url, $datos)
$img = $datos[1];

echo $img;

это HTML изображения, которое я ищу:

<img width="72" height="72" alt="" class="bo img" src="https://scontent-mia3-2.xx.fbcdn.net/v/t1.0-1/cp0/e15/q65/p74x74/21151613_1725782907724134_7535903357386699205_n.jpg?efg=eyJpIjoiYiJ9&amp;oh=4f22a577f965566b2016ef842f5b110f&amp;oe=5A1DE043">

я занимаю class чтобы определить изображение, но я не знаю, где ошибка.

 3
Author: Mariano, 2017-08-31

1 answers

С регулярным выражением (Не рекомендуется)

Как я уже говорил, регулярное выражение, которое вы используете, идеально соответствует HTML вашего вопроса (см. demo). Однако использование regex для этого не рекомендуется. Например:

  • Вы не считаете, что он находится внутри тега <img>, Поэтому с <input type='text' value'class="bo img" src="url.jpg"'> у вас будет проблема... и ее можно легко исправить, но ...
  • с другим атрибутом между классом и URL-адресом, например пример class="bo img" data-ejemplo="bla" src="url.jpg" у вас будет проблема... и ее можно легко исправить, но ...
  • , просто изменив порядок классов class="bo img" у вас будет проблема... и ее можно легко исправить, но ...
  • если эта часть HTML прокомментирована, например, в <!-- <img class="bo img" src="url.jpg"> --> у вас будет проблема... и это можно исправить, но ...
  • в синтаксисе HTML всегда будет какое-то нетрадиционное правило, которое усложняет вам все, и что сделайте так, чтобы ваше регулярное выражение не совпадало с тем, что вы не думали, что может произойти.

Вероятно, более целесообразно изменить его на что-то вроде: см. в regex101

#<img\b(?=[^>]*\sclass\s*=\s*"(?=[^"]*\bbo\b)[^"]*\bimg\b)[^>]*\ssrc\s*=\s*"([^"]*)"#i

Но все же это потерпит неудачу во многих случаях.



Использование DOM (рекомендуется)

Вы не должны использовать регулярные выражения для обработки HTML. На уровне, на котором вы поднимаете свое выражение, небольшое изменение HTML приведет к сбою вашего регулярного выражения. Лишнее пространство, изменение атрибутов tag, комментарий или более сложные структуры приведут к тому, что даже гигантское регулярное выражение не будет следовать правилам. Даже с очень продвинутым выражением может быть сгенерирован почти отказоустойчивый случай, но вы почти всегда можете найти редкий случай , который приводит к его сбою. Кроме того, для этого потребуется эксперт каждый раз, когда вы хотите его изменить.

Очень просто обрабатывать HTML с помощью дом, это инструменты, которые для этого.


Если у нас есть HTML, как показано ниже:

$html = '
    <img class="img" src="ejemplo1.jpg">
    <img width="72" height="72" alt="" class="bo img" src="https://scontent-mia3-2.xx.fbcdn.net/v/t1.0-1/cp0/e15/q65/p74x74/21151613_1725782907724134_7535903357386699205_n.jpg?efg=eyJpIjoiYiJ9&amp;oh=4f22a577f965566b2016ef842f5b110f&amp;oe=5A1DE043">
    <img class="bo etc" src="ejemplo2.jpg">
    <img class="bo etc img" src="ejemplo3.jpg">
';

DOM просто генерируется следующим образом:

//Englobamos en body para corregirlo y que lo procese bien
$html = "<body>$html</body>";

//Generar el DOM
$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_COMPACT | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_HTML_NODEFDTD);

И мы можем получить все изображения внутри DOM с помощью:

$img_nodelist = $dom->getElementsByTagName('img');

Чтобы пройти через них с помощью

foreach ($img_nodelist as $img) {
    // ...
}

Получение классов из каждого с:

$clases = $img->getAttribute('class');

И URL изображения с:

$urlImagen = $img->getAttribute('src');

Примечание: его также можно искать с помощью XPath, который намного меньше кода (и, безусловно, будет выполнять что-то быстрее), но я предпочел объяснить это так, более явным, чтобы сделать его более ясным.


Код:

//Ingreso
$html = '
    <img class="img" src="ejemplo1.jpg">
    <img width="72" height="72" alt="" class="bo img" src="https://scontent-mia3-2.xx.fbcdn.net/v/t1.0-1/cp0/e15/q65/p74x74/21151613_1725782907724134_7535903357386699205_n.jpg?efg=eyJpIjoiYiJ9&amp;oh=4f22a577f965566b2016ef842f5b110f&amp;oe=5A1DE043">
    <img class="bo etc" src="ejemplo2.jpg">
    <img class="bo etc img" src="ejemplo3.jpg">
';

//Englobamos en body para corregirlo y que lo procese bien
$html = "<body>$html</body>";

//Generar el DOM
$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_COMPACT | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_HTML_NODEFDTD);


//Obtener todas las imágenes
$img_nodelist = $dom->getElementsByTagName('img');

//Recorrer cada una
foreach ($img_nodelist as $img) {
    //Obtener la lista de clases
    $clases = $img->getAttribute('class');
    $clases_arr = explode(' ', $clases);

    //Ver si contiene ambas clases
    $clases_buscadas = array('bo', 'img');
    if (!array_diff($clases_buscadas, $clases_arr)) { //Contiene las clases
        //Obtener el SRC
        $urlImagen = $img->getAttribute('src');
        echo "URL: $urlImagen\n";
    }
}

Результат:

URL: https://scontent-mia3-2.xx.fbcdn.net/v/t1.0-1/cp0/e15/q65/p74x74/21151613_1725782907724134_7535903357386699205_n.jpg?efg=eyJpIjoiYiJ9&oh=4f22a577f965566b2016ef842f5b110f&oe=5A1DE043
URL: ejemplo3.jpg

Демо:

запустить в 3v4l.org

 4
Author: Mariano, 2017-08-31 03:51:14