読者です 読者をやめる 読者になる 読者になる

まめ畑

ゆるゆると書いていきます

Twitterで特定の人の発言を捕捉するクライアント-ソース編-

Twitter PHP

昨日のエントリーで書いた、特定の人の発言を捕捉するサイトのソースを曝しておきます。
全く高度なことはやっていないので、みればすぐにわかるかと思います。
作成意図は、面白いことを言う人や、情報系Botの発言を追跡するためのものです。
なので、発言機能などはありません。
みーてーるーだーけー。の状態です。

ドコモ専用です。
IDとパスワードは将来の拡張用です。


画像のPNG→Jpegを行うファイルの名前が逆です。
間違ってます・・・。

サイトメイン

<?php
header("Content-type: application/xhtml+xml" );

require_once './OreOreTwitter.php';

//将来用の設定
define("USER","ID");
define("PASS","PASS");

//さかのぼる最大のページ数を指定
define("MAX_PAGE", 10);

//ページ送り・戻しを作成
function makeArrow($sname, $page=1){
   $arrow = "<div style=\"text-align:center;\">\n";
   if($page == 1){
	$arrow .= "<a href=\"./?sname={$sname}&page=". ++$page ."\"> &gt;&gt; </a>";
   }elseif($page > 1 && $page < MAX_PAGE){
        $tPage = $page; 
	$arrow .= "<a href=\"./?sname={$sname}&page=". --$page ."\">  &lt;&lt;  </a><a href=\"./?sname={$sname}&page=". ++$tPage ."\"> &gt;&gt; </a>";
   }elseif($page == MAX_PAGE){
	$arrow .= "<a href=\"./?sname={$sname}&page=". --$page ."\"> &lt;&lt; </a>";
   }

   $arrow .= "\n</div>\n";
   return $arrow;
}

//確認したいユーザの名前を列挙
//TODO:外部から読み込めるように
$friends = array("ID1","ID2");
$options = "";

//リストの作成
foreach($friends as $friend){
	$options .= "<option value=\"{$friend}\">{$friend}</option>\n\t\t\t\t\t";
}

$userTl = "";
$screenName = "";
$dispName = "";

//送信されたデータを取得
if(isset($_GET["sname"])){
   $screen_name = $_GET["sname"];
   $page = (isset($_GET["page"])) ? $_GET["page"] : 1;
   $arrow = makeArrow($screen_name, $page);

	//タイムラインを取得
	$screenName = $screen_name;
	$oreore = new OreOreTwitter(USER,PASS);
	$oreore->setScreenName($screenName);
	$body = $oreore->getResDom($page);
	$image = mb_convert_encoding($oreore->getUserImage($body), "SJIS", "UTF-8");
	$tls = $oreore->getFriendTimeLine($body, $page);
   
   //PNG形式の画像だったら変換するようにアドレスを変更
   $imageUrl = (ereg(".+.(jpg|jpeg)$", $image)) ? $image : "./jpToPn.php?iurl={$image}";
	$dispName = "<br />\n<img src=\"{$imageUrl}\" width=\"50px\" height=\"50px\"/><br />\n";

	$dispName .= "<span style=\"color:orange;\">★</span>現在{$screenName}さんを表示中\n";
	$userTl .= "<div style=\"font-size:small;\">\n";

   //タイムラインを整形する
	foreach($tls as $tl){
	   $tml = mb_convert_encoding($tl["message"], "SJIS", "UTF-8");
	   $tml .= "\n<br />\n<div style=\"text-align:right; color:gray;\">".$tl["date"]."</div>\n";
	   $userTl .= "{$tml}\n<hr />\n";
	}
        $userTl .= $arrow;
	$userTl .= "</div>\n";
}

print <<< EOD
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/2.3) 1.0//EN" "i-xhtml_4ja_10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="content-Type" content="application/xhtml+xml; charset=Shift_JIS" />
		
		<title>Stokker for mobile</title>
	</head>
	<body style="background-color:rgb(154,228,232);">
		<div style="text-align:center;">
		   <br />
			<form action="./" method="get">
				<select name="sname">
					{$options}
				</select>
				<input type="submit" value="追跡" />
			</form>
				{$dispName}
			<hr />
		</div>
		<br />
			{$userTl}
	   <br />
	   <span style="font-size:small;">
	      Copyright &copy; 2008 YUTA. All Rights Reserved.
           </span>
	</body>
<html>
EOD;
?>

Webをスクレイピングして特定ユーザの発言を連想配列で返す

  • OreOreTwitter.php
<?php
require_once 'HTTP/Request.php';

define("USER_TIMELINE","http://twitter.com/");

class OreOreTwitter{

	protected $userId;
	protected $password;
	protected $screenName = "";

	//IDとPASSは将来の拡張用
	public function OreOreTwitter($userId = "", $password = ""){
		$this->userId = $userId;
		$this->password = $password;
	}

	//取得するユーザIDを設定
	public function setScreenName($screenName){
		$this->screenName = $screenName;
	}

	//ユーザタイムラインのDOMを取得
	public function getResDom($page = 1){
	   if($this->screenName == ""){
              throw new Exception("Screen Name is NOT SET");
           }
           $request = new HTTP_Request(USER_TIMELINE . $this->screenName . "?page=" . $page);
           $respons = $request->sendRequest();
           if(PEAR::isError($respons)){
              throw new Exception("Timeline get ERROR");
           }
           $dom = @DOMDocument::loadHTML($request->getResponseBody());
	   return $dom;
	}

	//ユーザのアイコンのアドレスを取得
	public function getUserImage($body){
	   $xml = simplexml_import_dom($body);
	   $image = $xml->xpath("//h2[@class=\"thumb\"]");
	   return (string)$image[0]->a[0]->img[0]["src"];
	}

	//フレンドタイムラインから発言などを取得
	public function getFriendTimeLine($body, $page){
	   $xml = simplexml_import_dom($body);
           $contents = array();
           $i = 0;

	 //どのページでも最新の発言が表示されるため2ページ目以降では除去
	 if($page == 1){
	   //各エントリを取得
	   $entry_top = $xml->xpath("//div[@class=\"desc hentry\"]");
	   //発言を取得
	   $content = strip_tags($entry_top[0]->p[0]->asXML()); 
	   $time = $entry_top[0]->xpath("p[@class=\"meta entry-meta\"]");
	   $time = $this->getJpTime((string)$time[0]->a[0]->abbr[0]["title"]);
	   $contents[$i++] = array("message"=>$content, "date"=>$time);
    }

         $entry_array = $xml->xpath("//td[@class=\"content\"]");
	   foreach($entry_array as $entry){
	      $time = $this->getJpTime((string)$entry->span[1]->a[0]->abbr[0]["title"]);
	      $content = strip_tags($entry->span[0]->asXML());
	      $contents[$i++] = array("message"=>$content, "date"=>$time);
	   }

	   return $contents;
	}

	//時刻の形式を日本時間へ変換
	protected function getJpTime($originTime){
	   return date("Y/m/d H:i:s",strtotime($originTime));
	}
}
?>

PNGからJPEGに変換

<?php
//PNGをJpegに変換
//GDモジュールがPNGをサポートしてないと動かない
if(isset($_GET["iurl"])){
	header("content-type: image/jpeg");

   //TODO 作成するJpeg画像のサイズを指定できるように
	$image = imagecreatefrompng($_GET["iurl"]);
	imagejpeg($image);
   imagedestroy($image);
}
?>

.htaccess

.htaccessで以下のように書いてください。

AddType application/x-httpd-php .xhtml
DirectoryIndex stokker.php

DirectoryIndexはあると便利なのでつけてます。
1行目が大切。


こんな感じです。
お恥ずかしい。