2016-06-14 7 views
2

Я получил содержимое этой веб-страницы http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369 и сохранил ее в $webpage.Пустой атрибут в DOM возвращает неожиданное резервное значение

ОБРАТИТЕ ВНИМАНИЕ:

В этой странице, есть целый ряд <meta> тегов. Один из этих мета-тегов является виновником и вызывает некоторые проблемы. Этот метатег: <meta property="og:description" content="" />. Обратите внимание, что значение content является пустой строкой.

Я читаю содержание веб-страницы следующим образом:

<?php 

$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369'; 

$webpage = file_get_contents($url); 

$og_entry_title = ""; 
$og_entry_content = ""; 

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

$meta_tags = $doc->getElementsByTagName('meta'); 

foreach ($meta_tags as $meta_tag) { 

    if ($meta_tag->getAttribute('property') == 'og:title') { 
     $og_entry_title = $meta_tag->getAttribute('content'); 
    } 

    if ($meta_tag->getAttribute('property') == 'og:description') { 
     $og_entry_content = $meta_tag->getAttribute('content'); 
    } 

} 

// print the results 
echo 
'$og_entry_title: ' . $og_entry_title 
.PHP_EOL. 
'$og_entry_content: ' . $og_entry_content; 

Когда я закончу, у меня есть следующие значения для $og_entry_title и $og_entry_content:

$og_entry_title: TOP STORIES | DW.COM 
$og_entry_content: News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment. 

Пожалуйста, обратите внимание на следующее в результате:

$og_entry_title является правильным и содержит название страницы, поэтому здесь нет проблем

$og_entry_content дает другое значение от ожидаемого. Я ожидал бы, что пустая строка будет сохранена в $og_entry_content; однако строка «Новости и анализ лучших международных и европейских тем Текущие и справочная информация по вопросам политики, бизнеса, науки, культуры, глобализации и окружающей среды». сохраняется. Эта строка представляется резервным значением (или значением по умолчанию), которое возвращается всякий раз, когда метатаг содержит пустую строку.

После дальнейшего расследования выяснилось, что go:description получает свое значение метатега с веб-страницы http://www.dw.com. Похоже, это произошло потому, что моя веб-страница содержала пустую строку. Возвращаемое значение извлекается с корневой страницы сайта.

У меня есть следующие вопросы о $og_entry_content:

  1. Как убедиться, что пустая строка (не значение запасного варианта) сохраняются в $og_entry_content?

  2. Почему это резервное значение с корневой страницы в любом случае возвращается?

Спасибо.

+1

Я не могу воспроизвести это. для меня, в конце скрипта 'var_dump ($ og_entry_content);' приводит к 'string (0)" "' –

+0

, не попробовал альтернативный 'get_meta_tags', глядя на этот конец, это должна быть пустая строка – Ghost

+0

@RodrigoDuterte - 'get_meta_tags' вызывает ту же проблему. – Greeso

ответ

1

Ответ

Ваш веб-адрес имеет специальные символы в нем, которые должны быть URL encoded.


Объяснение

Прежде всего, предположение о том, что ...

$og_entry_title правильно и содержит заголовок страницы, поэтому никаких проблем здесь

... не так.

Это название:

<meta property="og:title" content="تقرير استخباري اميركي: القاعدة تسيطر على غرب العراق | أخبار | DW.COM | 28.11.2006" /> 

не то же самое, как это название:

<meta property="og:title" content="TOP STORIES | DW.COM" /> 

Во-вторых, большинство современных браузеров достаточно удивительным, чтобы сделать кодировку URL на лету и по-прежнему отображаются специальные символы в адресной строке.

Вы можете загрузить see the response headers с веб-сервера.

<?php 
$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369'; 
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, "$url"); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($ch, CURLOPT_VERBOSE, 1); 
curl_setopt($ch, CURLOPT_HEADER, 1); 
$response = curl_exec($ch); 

// Then, after your curl_exec call: 
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 
echo ' 
header 
------ 
'.substr($response, 0, $header_size); 

Результаты показывают, что он не признает связь между URL и этой страницы:

header 
------ 
HTTP/1.1 301 Moved Permanently 
Server: Apache-Coyote/1.1 
Location:/
Content-Length: 0 
Accept-Ranges: bytes 
X-Varnish: 99639238 
Date: Thu, 16 Jun 2016 15:42:51 GMT 
Connection: keep-alive 

HTTP Response Code 301 является уведомление (постоянно) перенаправление на другую страницу. Location: / указывает, что вы должны просто перейти на home page. Это обычная неряшливая практика, чтобы просто отправить кого-то на домашнюю страницу, когда они не знают, что с вами делать.

Curl не будет следовать перенаправлениям по умолчанию, так как мы можем изучить заголовок ответа 301. Но file_get_contents будет следовать переадресации, поэтому вы получаете различный контент, чем ожидаете. (С возможными исключениями: есть bug report где некоторые замечает, что это не всегда следует переадресации.)

Обратите внимание, что страница делает есть content в его og:description:

<?php 
echo file_get_contents('http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369'); 

Результатов в этом выход:

...

<meta property="og:description" content="News and analysis of the top international and European topics Current affairs and background information on poltics, business, science, culture, globalization and the environment. " /> 

...

<meta property="og:title" content="TOP STORIES | DW.COM" /> 

...


Решение

Первое, что вам нужно сделать, это rawurlencode веб-адрес:

$url = rawurlencode($url); 

Затем реализовать что rawurlencode плохо назван, потому что valid URL будет содержать HTML-протокол http:// или https:// и также может содержать слэши для разграничения деталей.Это проблематично, потому что rawurlencode преобразует двоеточия : в %3A и косые черты / в %2F, что делает неправильный URL-адрес, например http%3A%2F%2Fwww.dw.com%2Far%2F.... Он должен был быть назван rawurlencode_parts_of_URL, но они не просили меня :) И процитировать Фил Карлтон в их защите:

Есть только два жесткие вещи в области компьютерных наук: кэш недействительность и именование вещи ,

Так конвертировать слэша и колон назад к своей первоначальной форме:

$url = str_replace('%3A',':',str_replace('%2F','/',$url)); 

Наконец, последнее, что вам нужно сделать, это send a header to your clients to let them know what kind of font encoding to expect.

header("content-type: text/html; charset=utf-8"); 

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

تÙ,Ø ± УСО ± Ø§Ø³ØªØ®Ø¨Ø§Ø ± US ا٠... УСО ± كي: ا٠«Ù,Ø§Ø¹Ø¯Ø © ØªØ³ÙŠØ · Ø ± ع٫٠‰ ØºØ ± ö ا٠«Ø¹Ø ± اÙ


Конечный продукт

<?php 

// let's see error output on screen while in development 
// remove these lines for production, and use log files only 
error_reporting(-1); 
ini_set('display_errors', 'On'); 

$url = 'http://www.dw.com/ar/تقرير-استخباري-اميركي-القاعدة-تسيطر-على-غرب-العراق/a-2251369'; 

// URL encode special chars 
$url = rawurlencode($url); 

// fix colons and slashses for valid URL 
$url = str_replace('%3A',':',str_replace('%2F','/',$url)); 

// make request 
$webpage = file_get_contents($url); 

$og_entry_title = ""; 
$og_entry_content = ""; 

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

$meta_tags = $doc->getElementsByTagName('meta'); 

foreach ($meta_tags as $meta_tag) { 

    if ($meta_tag->getAttribute('property') == 'og:title') { 
     $og_entry_title = $meta_tag->getAttribute('content'); 
    } 

    if ($meta_tag->getAttribute('property') == 'og:description') { 
     $og_entry_content = $meta_tag->getAttribute('content'); 
    } 

} 

// set the character set for the client 
header("content-type: text/html; charset=utf-8"); 

// print the results 
echo 
'$og_entry_title: ' . $og_entry_title 
.PHP_EOL. 
'$og_entry_content: ' . $og_entry_content; 

Результаты в этом выводе:

$og_entry_title: تقرير استخباري اميركي: القاعدة تسيطر على غرب العراق | أخبار | DW.COM | 28.11.2006 
$og_entry_content: 

Добавление

Если вы смотрите на ваши error logs, и вы действительно должны всегда быть просмотр журналов ошибок при разработке, то вы заметите литию предупреждений:

Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 4 in ... 

Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 5 in ... 

Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 6 in ... 

Warning: DOMDocument::loadHTML(): htmlParseStartTag: misplaced <html> tag in Entity, line: 7 in ... 

Warning: DOMDocument::loadHTML(): ID topMetaInner already defined in Entity, line: 300 in ... 

Warning: DOMDocument::loadHTML(): ID langSelectTrigger already defined in Entity, line: 315 in ... 

Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 546 in ... 

Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 546 in ... 

Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 548 in ... 

Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 548 in ... 

Это потому, что вы пытаетесь использовать класс DOMDocument с in-valid HTML and not well-formed XML documents. Но это тема для другого вопроса.

+0

Спасибо за удивительный подробный ответ. Я сделал все, что вы упомянули, но я все еще получаю эту проблему. Я думаю, что это проблема с тем, что сервер не отправил мне правильную страницу для начала. Я еще раз исследую. – Greeso

+0

действительно? вы * не * получаете тот же результат вывода, который я показываю при запуске сценария «Final Product»? Я обновил ответ, чтобы показать ошибки на экране. Каков ваш результат? –