刮HN Front Page - Handeling Simple HTML Dom Error

时间:2012-02-15 20:55:12

标签: php xml dom web-scraping bootswatch

我正在使用“简单的HTML Dom”来抓取HN Front Page(news.ycombinator.com),它在当时的大多数中运行良好。

然而,他们偶尔会推销一个缺乏刮刀所需元素的工作/公司,即得分,用户名和评论数量。

Shameless Promotion

这当然会破坏数组,从而打破我脚本的输出:

 <?php

// 2012-02-12 Maximilian (Extract news.ycombinator.com's Front Page)

// Set the header during development
//header ("content-type: text/xml");

// Call the external PHP Simple HTML DOM Parser (http://simplehtmldom.sourceforge.net/manual.htm)
include('lib/simple_html_dom.php');

date_default_timezone_set('Europe/Berlin');

// Download 'news.ycombinator.com' content
//$tmp = file_get_contents('http://news.ycombinator.com');
//file_put_contents('get.tmp', $tmp);

// Retrieve the content
$html = file_get_html('tc.tmp');

// Set the extraction pattern for each item
$title = $html->find("tr td table tr td.title a");
$score = $html->find("tr td.subtext span");
$user = $html->find("tr td.subtext a[href^=user]");
$link = $html->find("tr td table tr td.title a");
$time = $html->find("tr td.subtext");
$additionals = $html->find("tr td.subtext a[href^=item?id]");

// Construct the feed by looping through the items
for($i=0;$i<29;$i++) {

$cr=1;

// Check if the item points to an external website
if (!strstr($link[$i]->href,'http')) {

$url = 'http://news.ycombinator.com/'.$link[$i]->href;
$description = "Join the discussion on Hacker News.";


} else {

$url = $link[$i]->href;

// Getting content here

if (empty($abstract)) {

$description ="Failed to load any relevant content. Please try again later.";

} else {

$description = $abstract;

}

}
// Put all the items together
  $result .= '<item><id>f'.$i.'</id><title>'.htmlspecialchars(trim($title[$i]->plaintext)).'</title><description><![CDATA['.$description.']]></description><pubDate>'.str_replace('  | '.$additionals[$i]->plaintext,'',str_replace($score[$i]->plaintext.' by '.$user[$i]->plaintext.' ','',$time[$i]->plaintext)).'</pubDate><score>'.$score[$i]->plaintext.'</score><user>'.$user[$i]->plaintext.'</user><comments>'.$additionals[$i]->plaintext.'</comments><id>'.substr($additionals[$i]->href,8).'</id><discussion>http://news.ycombinator.com/'.$additionals[$i]->href.'</discussion><link>'.htmlspecialchars($url).'</link></item>'; 
}

$output = '<rss><channel><id>news.ycombinator.com Frontpage</id><buildDate>'.date('Y-m-d H:i:s').'</buildDate>'.$result.'</channel></rss>';

file_put_contents('tc.xml', $output);


?>

以下是正确输出的示例

<item>
<id>f0</id>
<title>Show HN: Bootswatch, free swatches for your Bootstrap site</title>
<description><![CDATA[Easy to Install Simply download the CSS file from the swatch of your choice and replace the one in Bootstrap. No messing around with hex values. Whole New Feel We've all been there with the black bar and blue buttons. See how a splash of color and typography can transform the feel of your site. Modular Changes are contained in just two LESS files, enabling modification and ensuring forward compatibility.]]></description>
<pubDate>3 hours ago</pubDate>
<score>196 points</score>
<user>parkov</user>
<comments>30 comments</comments>
<id>3594540</id>
<discussion>http://news.ycombinator.com/item?id=3594540</discussion>
<link>http://bootswatch.com</link>
</item>
<item>
<id>f1</id>
<title>Louis CK inspires Jim Gaffigan to sell comedy special for $5 online</title>
<description><![CDATA[Dear Internet Friends,Inspired by the brilliant Louis CK, I have decided to debut my all-new hour stand-up special on my website, Jimgaffigan.com.Beginning sometime in April, “Jim Gaffigan: Mr. Universe” will be available exclusively for download for only $5. A dollar from each download will go directly to The Bob Woodruff Foundation; a charity dedicated to serving injured Veterans and their families.I am confident that the low price of my new comedy special and the fact that 20% of each $5 download will be donated to this very noble cause will prevent people from stealing it. Maybe I’m being naïve, but I trust you guys.]]></description>
<pubDate>57 minutes ago</pubDate>
<score>25 points</score>
<user>rkudeshi</user>
<comments>4 comments</comments>
<id>3595285</id>
<discussion>http://news.ycombinator.com/item?id=3595285</discussion>
<link>http://www.whosay.com/jimgaffigan/content/218011</link>
</item>

这是一个错误输出的例子。请注意,元素不是空的,因此我似乎无法捕获错误并只是跳转到下一个项目。升级后的所有内容都会破裂:

<item>
<id>f14</id>
<title>Build the next Legos: We're hiring an iOS Developer &amp; Web Developer (YC S11)</title>
<description><![CDATA[Interested in building the next generation of toys on digital devices such as the iPad? That’s what we’re doing here at Launchpad Toys with apps like Toontastic (Named one of the “Top 10 iPad Apps of 2011” by the New York Times and was recently added to the iTunes Hall of Fame) and an awesom]]><![CDATA[e suite of others we have under development. We’re looking for creative and playful coders that have made games or highly visual apps/sites in the past for our two open development positions. As a kid, you probably played with Legos endlessly and grew up to be a hacker because you still love building things. Sounds like you? Email us at howdy@launchpadtoys.com with a couple links to some projects and code that we can look at along with your resume.]]></description>
<pubDate>2 hours ago</pubDate>
<score>14 points</score>
<user>bproper</user>
<comments>7 comments</comments>
<id>3594944</id>
<discussion>http://news.ycombinator.com/item?id=3594944</discussion>
<link>http://launchpadtoys.com/blog/2012/02/iosdeveloper-webdeveloper/</link>
</item>
<item>
<id>f15</id>
<title>SOPA foe Fred Wilson supports a blacklist on pirate sites</title>
<description><![CDATA[VC Fred Wilson says Google, Bing, Facebook, and Twitter should warn people when they try to log in at known pirate sites: "We don't need legislation." Fred Wilson says: If they try to pass antipiracy legislation, it will once again be 'war.' (Credit: Greg Sandoval/CNET) Fred Wilson, a well-known ven]]><![CDATA[ture capitalist from New York, says he's in favor of creating a blacklist for Web sites found to traffic in pirated films, music, and other intellectual property. The co-founder of Union Square Ventures told a gathering of media executives at the Paley Center for Media yesterday that he believes a good antipiracy measure would be for Google, Twitter, Facebook, and other major sites to issue warnings to people when they try to connect with a known pirate site. Fred Wilson, a co-founder of Union Square Ventures, says 'Our children have been taught to steal.' (Credit: Union Square Ventures) Wilson favors establishing an independent group to create a "black and white list." "The blacklist are those sites we all know are bad news," he told the audience in New York.]]></description>
<pubDate>14 points by bproper 2 hours ago  | 7 comments</pubDate>
<score>24 points</score>
<user>andrewcross</user>
<comments>12 comments</comments>
<id>3594558</id>
<discussion>http://news.ycombinator.com/item?id=3594558</discussion>
<link>http://news.cnet.com/8301-31001_3-57377862-261/post-sopa-influential-tech-investor-favors-blacklisting-pirate-sites/</link>
</item>

所以这是我的问题:我如何处理缺少特定元素并且find()不会抛出错误的情况?我是否必须从头开始,或者是否有更好的方法来抓取HN首页?

对于任何好奇的人,这是整个XML文件:http://thequeue.org/api/tc.xml

2 个答案:

答案 0 :(得分:1)

你必须通过块来处理它,似乎有一个虚拟的spacer元素可以帮助你:

$news = preg_split('/<tr style="height:5px"><\/tr>/',$html->find('tbody',2)->innertext);

然后使用子选择器:

foreach($news as $article){
    $article = str_get_html($article)
    // No upvote arrow found so its not a valid article
    if(count($article->find('img')) === 0){
        continue;
    }
}

对于其他元素,您使用相同的选择器

答案 1 :(得分:0)

我们要感谢Ivan的思路,我现在将最初抓取的HTML分成一个数组,每个节点代表一个帖子。然后,通过循环中的每个帖子,我将检查是否存在向上投票箭头图像。如果没有,我不会将其添加到结果中。最后,所有东西都将被拼接在一起,赞助的帖子被遗漏了。这是代码:

$array = explode('<tr style="height:5px"></tr>',$html);
foreach ($array as $post) {

    if (!strstr($post,'grayarrow.gif')){}else{

    $clean .=  $post;

    }

}
unset($array);
$html = str_get_html($clean.'</body></html>');