【问题标题】:Parsing XML using curl returning null使用返回 null 的 curl 解析 XML
【发布时间】:2019-03-28 02:59:22
【问题描述】:

我正在尝试解析 RSS 提要,但我得到的似乎是一个空的 DOM 文档对象。我当前的代码是:

$xml_url = "https://thehockeywriters.com/category/san-jose-sharks/feed/";

    $curl = curl_init();
    curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
    curl_setopt( $curl, CURLOPT_URL, $xml_url );

    $xml = curl_exec( $curl );
    curl_close( $curl );

    //$xml = iconv('UTF-8', 'UTF-8//IGNORE', $xml);
    //$xml = utf8_encode($xml);
    $document = new DOMDocument;
    $document->loadXML( $xml ); 
    if( ini_get('allow_url_fopen') ) {
      echo "allow url fopen? Yes";
    }
    echo "<br />";
    var_dump($document);

    $items = $document->getElementsByTagName("item");

    foreach ($items as $item) {
        $title = $item->getElementsByTagName('title');
        echo $title;
    }

    $url = 'https://thehockeywriters.com/category/san-jose-sharks/feed/';
    $xml = simplexml_load_file($url);
    foreach ($items as $item) {
        $title = $item->title;
        echo $title;
    }
    print_r($xml);
    echo "<br />";
    var_dump($xml);
    echo "<br />hello?";

此代码是根据在堆栈溢出时发现的以下示例中给出的答案和建议来解析相同 url 的两次单独尝试:
Example 1
Example 2

我尝试过或查找过的事情:
1. 检查以确保允许allow_url_fopen
2.确保有UTF编码
3. 验证 XML
4. 之前链接的 Stack Overflow 帖子中提供的代码示例

这是我当前的输出,var_dumpsecho's

allow url fopen? Yes
object(DOMDocument)#2 (34) { ["doctype"]=> NULL ["implementation"]=> string(22) "(object value omitted)" 
["documentElement"]=> NULL ["actualEncoding"]=> NULL ["encoding"]=> NULL 
["xmlEncoding"]=> NULL ["standalone"]=> bool(true) ["xmlStandalone"]=> bool(true) 
["version"]=> string(3) "1.0" ["xmlVersion"]=> string(3) "1.0" 
["strictErrorChecking"]=> bool(true) ["documentURI"]=> NULL ["config"]=> NULL 
["formatOutput"]=> bool(false) ["validateOnParse"]=> bool(false) ["resolveExternals"]=> bool(false) 
["preserveWhiteSpace"]=> bool(true) ["recover"]=> bool(false) ["substituteEntities"]=> bool(false) 
["nodeName"]=> string(9) "#document" ["nodeValue"]=> NULL ["nodeType"]=> int(9) ["parentNode"]=> NULL 
["childNodes"]=> string(22) "(object value omitted)" ["firstChild"]=> NULL ["lastChild"]=> NULL 
["previousSibling"]=> NULL ["attributes"]=> NULL ["ownerDocument"]=> NULL ["namespaceURI"]=> NULL 
["prefix"]=> string(0) "" ["localName"]=> NULL ["baseURI"]=> NULL ["textContent"]=> string(0) "" } 
bool(false) 
hello?

【问题讨论】:

  • 您之前看到的答案都没有使用 SSL。看看stackoverflow.com/questions/4372710/php-curl-https我认为问题是证书。
  • 嗯,我尝试了 quickfix curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, false); 只是想看看它是否有效,但它没有。另外,我想这也是一个安全问题。

标签: php xml domdocument


【解决方案1】:

我对您的代码的唯一问题是不定义用户代理会给我错误 403 以访问提要。

将来,您可以使用curl_getinfo 提取请求的状态码,以确保它没有失败,并进一步将其与代码 200 进行匹配,即 OK。

$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

除了循环中的一些错误。

使用 SimpleXML:

<?php
$url = "https://thehockeywriters.com/category/san-jose-sharks/feed/";

$curl = curl_init();
curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_URL, $url);
$data = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);

if ($httpcode !== 200)
{
    echo "Failed to retrieve feed... Error code: $httpcode";
    die();
}

$feed = new SimpleXMLElement($data);
// list all titles...
foreach ($feed->channel->item as $item)
{
    echo $item->title, "<br>\n";
}

使用 DOMDocument:

<?php
$url = "https://thehockeywriters.com/category/san-jose-sharks/feed/";

$curl = curl_init();
curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_URL, $url);
$data = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);

if ($httpcode !== 200)
{
    echo "Failed to retrieve feed... Error code: $httpcode";
    die();
}

$xml = new DOMDocument();
$xml->loadXML($data);
// list all titles...
foreach ($xml->getElementsByTagName("item") as $item)
{
    foreach ($item->getElementsByTagName("title") as $title)
    {
        echo $title->nodeValue, "<br>\n";
    }
}

如果您只想打印所有项目的标题/描述:

foreach ($feed->channel->item as $item)
{
    echo $item->title;
    echo $item->description;
    // uncomment the below line to print only the first entry.
    // break;
}

如果您只想要第一个条目,而不使用 foreach:

echo $feed->channel->item[0]->title;
echo $feed->channel->item[0]->description;

将标题和描述保存到数组中以供以后使用:

$result = [];
foreach ($feed->channel->item as $item)
{
    $result[] = 
    [
        'title' => (string)$item->title,
        'description' => (string)$item->description
    ];
    // could make a key => value alternatively from the above with 
    // title as key like this: 
    // $result[(string)$item->title] = (string)$item->description;
}

使用 MySQLi/PDO 准备好的 Foreach 语句:

foreach ($feed->channel->item as $item)
{
    // MySQLi
    $stmt->bind_param('ss', $item->title, $item->description);
    $stmt->execute();
    // PDO
    //$stmt->bindParam(':title', $item->title, PDO::PARAM_STR);
    //$stmt->bindParam(':description', $item->description, PDO::PARAM_STR);
    //$stmt->execute();
}

【讨论】:

  • 只要我添加了用户代理行,我就可以让它工作。谢谢你。就像你提到的那样,也修复了循环。
  • @KurtLeadley 您可以进一步使用$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 来验证代码是否为 200,以确保您也获得了数据,请参阅更新的代码。
  • 啊,非常好。我需要对 curl 选项进行更多研究。
【解决方案2】:

我选择了 Prix 的答案来指出用户代理定义,但我想出了另一种执行循环的方法,它可以避免嵌套循环并更容易访问其他节点。这是我正在使用的(DOM 文档解决方案):

$xml_url = "https://thehockeywriters.com/category/san-jose-sharks/feed/";

$curl = curl_init();
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $curl, CURLOPT_URL, $xml_url );
curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0");

$xml = curl_exec( $curl );
curl_close( $curl );

$document = new DOMDocument;
$document->loadXML( $xml ); 

$items = $document->getElementsByTagName("item");       
foreach ($items as $item) {     
    $title = $item->getElementsByTagName('title')->item(0)->nodeValue;
    echo $title;
    $desc = $item->getElementsByTagName('description')->item(0)->nodeValue;
    echo $desc;
}

【讨论】:

  • 我还是更喜欢 SimpleXML,我觉得它使用起来更直接,我添加了 3 个其他示例来向您展示。
  • 我明白了!这很棒。下次我有选择。我碰巧有一个与我刚刚发布的代码类似的工作版本,所以我就去了。我有兴趣尝试阵列一。数组解决方案可以减少 SQL 插入查询吗?现在我每个循环都插入到我的数据库中。
  • 如果您使用像 codeigniter 这样的框架,您可以将其用于批量插入,但这几乎是一个幕后循环。只需确保您使用准备好的语句将所有数据绑定到您的 foreach 中,以避免以后头疼。
  • 在底部添加了一个示例,说明使用 MySQLi bind_param 和 foreach 会是什么样子,以防万一;)
  • 谢谢,我已经被大喊大叫了,我知道更好,总是使用准备好的陈述哈哈。已经从我的网站数据库中提取了三月的文章 :) sjsharktank.com/index.php
猜你喜欢
  • 2013-08-15
  • 2021-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多