Не удается получить заголовок с веб-страницы - PullRequest
0 голосов
/ 06 октября 2018

Я написал скрипт на php для удаления title , видимого как shamboo для выпадения волос с веб-страницы.Когда я выполняю свой скрипт ниже, я получаю следующую ошибку:

Примечание: Попытка получить свойство 'nodeValue' необъекта в C: \ xampp \ htdocs \ runcode \ testfile.php на линии16.

Ссылка на этот сайт

Скрипт, с которым я пробовал:

<?php
    function get_content($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_exec($ch);
        $htmlContent = curl_exec($ch);
        curl_close($ch);
        return $htmlContent;
    }
    $link = "https://www.purplle.com/search?q=hair%20fall%20shamboo"; 
    $xml = get_content($link);
    $dom = @DOMDocument::loadHTML($xml);
    $xpath = new DOMXPath($dom);
    $title = $xpath->query('//h1[@class="br-hdng"]/span')->item(0)->nodeValue;
    echo "{$title}";
?>

Мой ожидаемый результат:

hair fall shamboo

Хотя xpath, который я использовал в моем вышеупомянутом скрипте, кажется правильным, я вставил сюда соответствующую часть html-элементов, внутри которой можно найти title:

<h1 _ngcontent-c0="" class="br-hdng"><span _ngcontent-c0="" class="pr dib">hair fall shamboo<!----></span></h1>

PostScript: title, который я хочу проанализировать, загружается динамически.Поскольку я новичок в php, я не понимаю, является ли способ, который я пробовал, точным.Если не то, что я должен делать тогда?

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

Я добился успеха, используя javascript:

const puppeteer = require('puppeteer');
function run () {
    return new Promise(async (resolve, reject) => {
        try {
            const browser = await puppeteer.launch();
            const page = await browser.newPage();
            await page.goto("https://www.purplle.com/search?q=hair%20fall%20shamboo");
            let urls = await page.evaluate(() => {
            let items = document.querySelector('h1.br-hdng span');
            return items.innerText;;
            })
            browser.close();
            return resolve(urls);
        } catch (e) {
            return reject(e);
        }
    })
}
run().then(console.log).catch(console.error);

Снова, я добился успеха, используя python:

import requests_html

with requests_html.HTMLSession() as session:
    r = session.get('https://www.purplle.com/search?q=hair%20fall%20shamboo')
    r.html.render()
    item = r.html.find("h1.br-hdng span",first=True).text
    print(item)

Что не так с php тогда?

Ответы [ 2 ]

0 голосов
/ 15 декабря 2018

Что тогда не так с php?

php не запускает javascript.по-видимому, puppeteer из вашего кода javascript, а также запрашиваемая_html из кода python, оба запускают javascript.

ваша проблема в том, что эта страница загружает заголовок br-hdng и продукты с помощью javascript, это не частьHTML вообще.все это фактически загружается из https://www.purplle.com/api/shop/itemsv3, с кучей параметров GET,.здесь вам нужно выполнить анализ JSON, а не HTML :), но прежде чем вы сможете получить доступ к этому API, вам нужны файлы cookie, предоставленные страницей поиска, и строка поиска должна соответствовать строке поиска API (в противном случае APIпросто вернет ошибки), проверьте это:

<?php
declare(strict_types = 0);
header ( "Content-Type: text/plain;charset=UTF-8" );
$ch = curl_init ();
curl_setopt_array ( $ch, array (
        CURLOPT_ENCODING => '',
        CURLOPT_COOKIEFILE => '', // enables cookie handling without saving them anywhere. this page requires cookie handling.
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0', // 'libcurl/? PHP/' . PHP_VERSION, // many websites block requests without a useragent
        CURLOPT_RETURNTRANSFER => 1 
) );
// we don't care what's on this page, we just need to fetch it to create a cookie session.
$search_query = 'hair fall shamboo';
curl_setopt ( $ch, CURLOPT_URL, 'https://www.purplle.com/search?q=' . rawurlencode ( $search_query ) );
curL_exec ( $ch );
$url = 'https://www.purplle.com/api/shop/itemsv3?' . http_build_query ( array (
        'list_type' => 'search',
        'custom' => '',
        'list_type_value' => $search_query,
        'page' => '1',
        'sort_by' => 'rel',
        'elite' => '0' 
) );
// $url = 'https://www.purplle.com/api/shop/itemsv3?list_type=search&custom=&list_type_value=hair%20fall%20shamboo&page=1&sort_by=rel&elite=0';
// $out = tmpfile ();
// curl_setopt_array ( $ch, array (
// CURLOPT_HTTPHEADER => array (
// 'Accept: application/json, text/plain, */*',
// 'Accept-Language: en-US,en;q=0.5',
// 'Referer: https://www.purplle.com/search?q=hair%20fall%20shamboo',
// // Cookie: __cfduid=d3199415b5ce18cbff2779802b1f843331544901552; csrftoken=f8f18b5deae92972f63343e13c6a460b; purpllesession=hedxkc%2FkdGye%2BYi6ebmJktUN1LeqA5rdVXu96%2F0j0yqtP2xZ8LfwpK8daXqPSkeZulO9ZvqpMYXTmY8oMD03VcG9vdKGBm30R9fU%2FQygtXBFhZvfvsu0scyaL3FqHbePp2zG45MevWU961eg82KAkCuHk0qFM8URQBRyYV5gg8TeqnTPgI3tF87H5nJ%2BmfO4pn%2BRWmIuWXvgNXAO%2F8GEaH6lJVl17QZm9c5vwi10OYeLfmSdIMy6V2Pp0ZjLTzuFw2de5jpR0zsbHHKZ0C2e548PiDl3taHIE5wuZO4HYIeXUqTpE98%2Fo3kztoU1bTlXGZgu%2FxVQ3EWLRFWQ2t57UawA%2FuERlD8vvOyFGbYHGAWVxgFTR%2FObAhFLHns5kqoj; _autm30d=null; visitorppl=NZ5tqQpGlFYWg2MrDl1302113161544901552; session_initiated=Direct; _tmpsess=1; token=desktop_5c1553b07c61c_7955_16122018; __uzma=5c1553b085a480.63440826; __uzmb=1544901552; __uzmc=632121030774; __uzmd=1544901552
// 'Connection: keep-alive'
// ),
// // CURLOPT_CONNECT_TO=>array('www.purplle.com:443:dumpinput.ratma.net:80'),
// CURLOPT_STDERR => $out,
// CURLOPT_VERBOSE => 1
// ) );
// var_dump ( $url );
curl_setopt ( $ch, CURLOPT_URL, $url );
$json = curl_exec ( $ch );
$data = json_decode ( $json, true );

// var_dump ($json, $data );
$title = $data ['list_title'];
echo 'title: ' . $title . "\n";
foreach ( $data ['items'] as $item ) {
    echo "name: ", $item ['name'], "\n";
}

вывод:

title: hair fall shamboo
name: VLCC Hair fall Shampoo 350 ML (Buy1 Get1) & Ayurveda Hair Oil Combo (470 ml)
name: Biotique Bio Kelp Protein Shampoo For Falling Hair (190 ml)
name: Biotique Fresh Texture Shampoo - Bio Henna Leaf (120 ml)
name: Good Vibes Scalp Purifying Shampoo -Neem And Aloe Vera (200 ml)
name: Khadi Shikakai Sat Hair Cleanser Scalp Therapy (210 ml) By Swati Gramodyog
name: Good Vibes Apple Cider Vinegar Shampoo (120 ml)
name: Good Vibes Refreshing Shampoo - Green Apple (200 ml)
name: Good Vibes Hydrating Shampoo -Marigold (200 ml)
name: Alps Goodness Smoothening Shampoo - Keratin (50 ml)
name: Alps Goodness Softening Shampoo - Coconut & Almond (50 ml)
name: Alps Goodness Split End Control Shampoo - Coconut, Garlic & Shea Butter (50 ml)
name: Passion Indulge Papain Shampoo & Conditioner For Soft & Shiny Hair (200 ml + 100 ml)
name: Good Vibes Apple Cider Vinegar Shampoo (200 ml)
name: Alps Goodness Split End Control Shampoo - Coconut, Garlic & Shea Butter (200 ml)
name: Alps Goodness Nourishing Shampoo - Argan Oil & Olive (200 ml)
name: Alps Goodness Moisturizing Shampoo - Ginger & Egg (200 ml)
name: Alps Goodness Conditioning Shampoo - Pure Honey (200 ml)
name: Alps Goodness Hydrating Shampoo - Tea Tree (200 ml)
name: Alps Goodness Smoothening Shampoo - Keratin (200 ml)
name: Alps Goodness Softening Shampoo - Coconut & Almond (200 ml)
name: Good Vibes Scalp Purifying Shampoo -Neem And Aloe Vera (120 ml)
name: Good Vibes Hydrating Shampoo - Marigold (120 ml)
name: Alps Goodness Conditioning Shampoo - Pure Honey (50 ml)
name: Alps Goodness Moisturizing Shampoo - Ginger & Egg (50 ml)
0 голосов
/ 07 октября 2018

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

DOMDocument::loadHTML() это не статический метод, а метод экземпляра (который возвращает логическое значение).Сначала вы должны создать экземпляр DOMDocument, а затем вызвать loadHTML() для этого экземпляра:

$dom = new DOMDocument;
$dom->loadHTML($xml);

Однако, поскольку вы подавили ошибки с помощью оператора @ в этой конкретной строке, вы неполучать предупреждение об этом.И хотя очень часто видно, что оператор подавления ошибок @ используется для подавления ошибок проверки HTML, например, вы должны использовать libxml_use_internal_errors() 1 , так какне подавляет общие ошибки PHP.

$dom = new DOMDocument;
$oldSetting = libxml_use_internal_errors(true);
$dom->loadHTML($xml);
libxml_use_internal_errors($oldSetting);

В качестве заключительного замечания:
Возможно загрузить документ DOM из URL-адреса напрямую (без необходимости cURL) с помощью DOMDocument::loadHTMLFile(), если ваша установка PHP настроена на загрузку URL-адресов через параметр конфигурации allow_url_fopen.Имейте в виду, что этот параметр часто отключается по соображениям безопасности, поэтому используйте его с осторожностью, если вы планируете его использовать.


Вот простой тестовый пример, который должен работать как положено:

<?php

$html = '
<html>
<head>
  <title>DOMDocument test-case</title>
</head>
<body>
  <div class="dummy-container">
    <h1 _ngcontent-c0="" class="br-hdng"><span _ngcontent-c0="" class="pr dib">hair fall shamboo<!----></span></h1>
  </div>
</body>';

$dom = new DOMDocument;

$oldSetting = libxml_use_internal_errors(true);
$dom->loadHTML( $html );
libxml_use_internal_errors($oldSetting);

$xpath = new DOMXPath( $dom );
$title = $xpath->query( '//h1[@class="br-hdng"]/span' )->item( 0 )->nodeValue;
echo $title;

См. Этот пример, интерпретируемый онлайн на 3v4l.org

Вы должны заменить содержимое $html выводом вашего get_content()вызов.Если это не работает, то либо:

  1. что-то не так с извлечением HTML с помощью cURL (сделайте var_dump( $html ); перед загрузкой в ​​DOMDocument, например, чтобы увидетьсодержимое, которое вы извлекли), или ...

  2. возможно, вы работаете в пространстве имен, и в этом случае вам следует добавить обратную косую черту перед DOMDocument и DOMXPath, то есть: new \DOMDocument; и new \DOMXPath( $dom );.


1.LibXML - это библиотека XML, которая используется DOMDocument для анализа документов XML / HTML.

...