i2i無料WEBパーツ
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
PHPCrawlでのクロールがとりあえず出来るようになりました。
ただ、クロールで循環した場合はどうなるのか?等の検証が出来ていませんので、
デバッグ以外で怖くて使えませんけど^^;

とりあえず、PHPCrawl一度まとめておきますと・・・。

PHPCrawlは、そのままで使うと
  • ・PHP5に対応していない為、ワーニングが出まくる。
  • ・robot.txtを見ない。
  • ・ページを読み込む間隔が設定されていないので、クローラー対象のWebサーバに負荷をかける危険性がある。
  • ・日本語は文字化けする。

といった事で、危険でかつ使えないって話になります。
対応としては、
  • ・phpcrawlerutils.class.phpのすべてのメソッドにpublic static をつける。
  • ・phpcraler.class.phpのinitCrawlerメソッドをオーバライドもしくは修正し、use_robots_txt_files = trueとし、robot.txtを判断するようにする。
  • ・phpcraler.class.phpのgoメソッドをオーバライドして1ページ1秒くらいのペースでクロールするようにsleepを追加する。
  • ・phpcrawlerpagerequest.class.phpで$source_readに読み込んだhtmlの内容をmb_convert_encodingかけて文字化けを回避する。

といったとこでしょうかねぇ・・・

まあ、私、PHPよくわかってないので、あまり参考にならんかもですが・・・PHPCrawlerを継承して作成したCustomizePhpCrawlerが下記のとおりです。

<?php
require_once('../../util/ScrapeUtil.class.php');

/**
* カスタマイズPHPクローラ
*/
class CustomizePhpCrawler extends PHPCrawler {

var $targetPage;

var $filter_text = array();
//ページを取得する間隔(秒)
var $sleepTime = 1.0;
//各ページの要素
var $pageElement = array();
/**
*
* @see util/PHPCrawler#initCrawler()
*/
function setTargetPage($page)
{
$this->targetPage =$page;
}

/**
* クロールした各ページの情報を取得します。
* @return array
*/
function getPageElement(){
return $this->pageElement;
}

/**
* goメソッドのオーバライド
* @see util/PHPCrawler#go()
*/
function go()
{
$starting_time = $this->getmicrotime();

// Init, split given URL into host, port, path and file a.s.o.
$url_parts = PHPCrawlerUtils::splitURL($this->url_to_crawl);

// Set base-host and base-path "global" for this class,
// we need it very often (i guess at this point...)
$this->base_path = $url_parts["path"];
$this->base_host = $url_parts["host"];
$this->base_domain = $url_parts["domain"];

// If the base port wasnt set by the user ->
// take the one from the given start-URL.
if ($this->base_port == "") $this->base_port = $url_parts["port"];

// if the base-port WAS set by the user
$url_parts["port"] = $this->base_port;

// Reset the base_url
$this->url_to_crawl = PHPCrawlerUtils::rebuildURL($url_parts);
$this->url_to_crawl = PHPCrawlerUtils::normalizeURL($this->url_to_crawl);

// Init counters
$links_followed=0;
$files_received=0;

// Put the first url into our main-array
$tmp[0]["url_rebuild"] = $this->url_to_crawl;
PHPCrawlerUtils::removeMatchingLinks($tmp, $this->not_follow_matches);

if (isset($tmp[0]["url_rebuild"]) && $tmp[0]["url_rebuild"] != "")
{
PHPCrawlerUtils::addToArray($tmp, $this->urls_to_crawl, $this->url_map, $this->store_extended_linkinfo);
}

// MAIN-LOOP -------------------------------------------------------------------

// It works like this:
// The first loop looks through all the "Priority"-arrays and checks if any
// of these arrays is filled with URLS.

for ($pri_level = $this->max_priority_level+1; $pri_level > -1; $pri_level--)
{
// Yep. Found a priority-array with at least one URL
if (isset($this->urls_to_crawl[$pri_level]) && !isset($stop_crawling))
{
// Now "process" all URLS in this priroity-array
@reset($this->urls_to_crawl[$pri_level]);
while (list($key) = @each($this->urls_to_crawl[$pri_level]))
{
//ページ取得を待機します。
sleep($this->sleepTime);

$all_start = $this->getmicrotime();

$stop_crawling_this_level = false; // init

// Request URL (crawl())
unset($page_data);

if (!isset($this->urls_to_crawl[$pri_level][$key]["referer_url"]))
{
$this->urls_to_crawl[$pri_level][$key]["referer_url"] = "";
}

$page_data = $this->pageRequest->receivePage($this->urls_to_crawl[$pri_level][$key]["url_rebuild"],
$this->urls_to_crawl[$pri_level][$key]["referer_url"]);

// If the request-object just irnored the URL ->
// -> Stop and remove URL from Array
if ($page_data == false)
{
unset($this->urls_to_crawl[$pri_level][$key]);
continue;
}

$links_followed++;

<略>

// If given, just follow "matching"-links
// (only follow given preg_matches)
if (count($this->follow_matches) > 0)
{
//follow_matchesとurltextが一致したリンクのみを対象とするように修正
//$links_found=&PHPCrawlerUtils::removeNotMatchingLinks($links_found, $this->follow_matches);
$links_found=&PHPCrawlerUtils::removeNotMatchingLinksAndText($links_found, $this->follow_matches, $this->filter_text);
}

// Add found and filtered links to the main_array urls_to_crawl
if ($this->benchmark == true) $bm_start = $this->getmicrotime();
PHPCrawlerUtils::addToArray($links_found, $this->urls_to_crawl, $this->url_map, $this->store_extended_linkinfo);
if ($this->benchmark == true) echo "addToArray(): ".($this->getmicrotime() - $bm_start)."<br>";

// If there is wasnt any content found so far (code 200) and theres
// a redirect location
// -> follow it, doesnt matter what follow-mode was choosen !
// (put it into the main-array !)
if (!isset($content_found) && $redirect != "" && $this->follow_redirects_till_content == true)
{
$rd[0]["url_rebuild"] = phpcrawlerutils::buildURL($redirect, $actual_url);
$rd[0]["priority_level"] = 0;
PHPCrawlerUtils::addToArray($rd, $this->urls_to_crawl, $this->url_map, $this->store_extended_linkinfo);
}

// Now we remove the actual URL from the priority-array
unset($this->urls_to_crawl[$pri_level][$key]);

// Now we check if a priority-array with a higher priority
// contains URLS and if so, stop processing this pri-array and "switch" to the higher
// one
for ($pri_level_check = $this->max_priority_level+1; $pri_level_check > $pri_level; $pri_level_check--)
{
if (isset($this->urls_to_crawl[$pri_level_check]) && $pri_level_check > $pri_level)
{
$stop_crawling_this_level = true;
}
}

// Stop crawling this level
if ($stop_crawling_this_level == true)
{
$pri_level = $this->max_priority_level+1;
break;
}

// Unset crawled URL, not nedded anymore
unset($this->urls_to_crawl[$pri_level][$key]);

// echo "All:".($this->getmicrotime()-$all_start);

} // end of loop over priority-array

// If a priority_level was crawled completely -> unset the whole array
if ($stop_crawling_this_level == false)
{
unset($this->urls_to_crawl[$pri_level]);
}

} // end if priority-level exists

} // end of main loop


// Loop stopped here, build report-array (status_return)

$this->status_return["links_followed"] = $links_followed;
$this->status_return["files_received"] = $files_received;
$this->status_return["bytes_received"] = $this->pageRequest->traffic_all;

$this->status_return["traffic_limit_reached"] = $page_data["traffic_limit_reached"];

if (isset($page_data["file_limit_reached"]))
{
$this->status_return["file_limit_reached"] = $page_data["file_limit_reached"];
}
else $this->status_return["file_limit_reached"] = false;

if (isset($page_data["user_abort"]))
{
$this->status_return["user_abort"] = $page_data["user_abort"];
}
else $this->status_return["user_abort"] = false;

if (isset($stop_crawling))
{
$this->status_return["limit_reached"] = true;
}
else {
$this->status_return["limit_reached"] = false;
}

// Process-time
$this->status_return["process_runtime"] = $this->getMicroTime() - $starting_time;

// Average bandwith / throughput
$this->status_return["data_throughput"] = round($this->status_return["bytes_received"] / $this->status_return["process_runtime"]);
}

/**
* page_dataを使ってゴニョゴニョスクレイピングする
* @see util/PHPCrawler#handlePageData($page_data)
*/
function handlePageData(&$page_data)
{
$encodeing = mb_detect_encoding($page_data["source"]);
$source = $page_data["source"];
$source = cleanString( $source );

$rdfItems = $this->targetPage->getRdfItems($source);
$count = 0;
foreach ($rdfItems as $rdfItem){
$count++;
//タイトル取得(dc:title)
$title = $this->targetPage->getTitle($rdfItem);
//URL取得(dc:identifier)
$url = $this->targetPage->getUrl($rdfItem);
//件名取得(dc:subject)
$subject = $this->targetPage->getSubject($rdfItem);
//(dc:date)
$date = $this->targetPage->getDate($rdfItem);
array_push($this->pageElement ,
array(
'title' => $title,
'url' => $url,
'subject' => $subject,
'date' => $date,
)
);
}
}
}
?>


CustomizePhpCrawlerでは、handlePageDataでページごとにスクレイピングしてます。
スクレイピングがまた、面倒なんだよねぇ・・・。正規表現得意じゃないし。
このCustomizePhpCrawlerを使ってスイスイーっと、自分のブログをクローリングしてみたのがこのプログラムです。


<?php

require_once('../../util/OutputUtil.class.php');
require_once('../../util/phpcrawlerutils.class.php');
require_once('../../util/phpcrawler.class.php');
require_once('../../entity/fc2page.class.php');
require_once('../../util/ScrapeUtil.class.php');

require_once('customizephpcrawler.class.php');

$url = $_POST['url'];
if($url == null){
$url = $_GET['url'];
}
if(is_null($url)){
//URLが正しくないのでエラー
echo ("URLを指定してください。"."<br>");
exit;
}
$Page = new Fc2Page;
if(preg_match($Page->getCheckUrlRegex(), $url, $matches)) {
//URLが正しくないのでエラー
echo ("URLが正しくありません:" . $url . "<br>");
exit;
}

$CustomizePhpCrawler = new CustomizePhpCrawler;
$CustomizePhpCrawler->setTargetPage($Page);

//最大取得ページ数を指定
$CustomizePhpCrawler->setPageLimit(5);
//クロールを開始するURLを指定
$CustomizePhpCrawler->url_to_crawl = $url;
//次のページに遷移するURLを取得する文字列を設定
$CustomizePhpCrawler->follow_matches = array($Page->getNextLinkUrlRegex());
//次のページに遷移するURLの正規表現を設定
$CustomizePhpCrawler->filter_text = array($Page->getNextLinkTextArray());
//クローリングを実行
$CustomizePhpCrawler->go();
//クローリング結果を取得します。
$crawlResult = $CustomizePhpCrawler->getPageElement();
//レポートを出力します。
$status_array = $CustomizePhpCrawler->getReport();

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-31j">
<link rel="stylesheet" type="text/css" href="../../css/main.css"/>
<title>phpcrawlerutils Test</title>
</head>
<body>
■CustomizePhpCrawler->getReport()の結果 $target_array<br>
<?php
OutputUtilClass::outTableFromKeyAndValues($status_array);
?>

■CustomizePhpCrawler->getPageElement()の結果 $crawlResult<br>
<?php
if(count($crawlResult) > 0) {
OutputUtilClass::outPageElement($crawlResult);
}else{
print "検索結果なし。<br>" ;
}
?>
<br>
</body>
</html>


出力結果はこんな感じになりますわ。まあ、ぼちぼち使えるかなぁ?



























日付タイトル
2009/06/29 06:33:01Windows Beep音の止め方
2009/06/28 06:06:45OSC 2009 NTTPCさんから豪華な粗品が届いた(汗
2009/06/27 07:09:45PHPのクローラについての調査 PHPCrawlの解析その6
2009/06/26 08:09:45Σ(・_・;)・・・マイケルジャクソンが?
2009/06/26 07:27:18GPLについての調査
2009/06/25 22:58:10PHPから投稿テスト
2009/06/25 07:51:35PHPのクローラについての調査 PHPCrawlの解析その5
2009/06/24 07:09:22PHPのクローラについての調査 PHPCrawlの解析その4
2009/06/23 07:49:27Oracleの不要セッション削除方法
2009/06/22 08:46:07オープンソースカンファレンス 2009 Hokkaidoに行ってきた
2009/06/21 07:11:23Google Booksがすごい
2009/06/20 06:53:45札幌のSEはブリッジSEなのかしら?
2009/06/19 07:31:18PL/SQLでランダムな値で更新する方法 日付編
2009/06/18 07:19:42PL/SQLでランダムな値で更新する方法
2009/06/17 07:11:14PHPのクローラについての調査 PHPCrawlの解析その3
2009/06/17 07:09:13ブログでソースコードを表示 google-code-prettify
2009/06/16 06:48:47PHPのクローラについての調査 PHPCrawlの解析その2
2009/06/15 15:45:57PHPのクローラについての調査 PHPCrawlの解析その1
2009/06/13 15:13:56札幌のパスタがおいしいイタリアン らめーら
2009/06/12 07:24:02PHPでWebページのサムネイルを作成する方法の調査
2009/06/11 21:39:07北海道のちょっとした驚くべきニュース
2009/06/10 23:52:14PHP・Webに関するTODO
2009/06/09 21:48:14Microsoftの新検索サービス「Bing」の感想
2009/06/07 18:32:58FC2でコンソール風に表示する方法
2009/06/07 10:56:10EclipseとPDTでデバック


コメント

コメントの投稿

  • URL
  • コメント
  • パスワード
  • 秘密
  • 管理者にだけ表示を許可する

トラックバック

トラックバックURL:http://kevinjohnson2.blog69.fc2.com/tb.php/211-6528e7f0
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。