2010年1月8日 星期五

[PHP] 使用官方 Plurk API 實作簡單的機器人 - 靠機器人救 Karma!以 Yahoo News 為例

Yahoo! News & Plurk


靠機器人救 Karma!由於 Karma 值的不穩定,乾脆實做一隻 Plurk 機器人好了,這次實做參考 [PHP] Official Plurk API 之PHP - cURL 使用教學


Update @ 2011/07/26:新增縮網址的程式碼,因為新聞連結長度超過 144 字數的限制。


整體上就是實做一個撈 Yahoo 新聞的小程式,理論上是要用 RSS 才對,但因為我只想看焦點新聞,所以就改撈他的首頁進行處理,可以自行更新 getNews 函數吧!而這隻程式可以搭配 Windows 的排程或是 Unix 的 Crontab 運作,而程式環境上還要求 PHP-Curl 的支援囉!由於它非常陽春,所以我連帳密錯誤都沒確認就是了 :P


<?php
$cookie_db = '/tmp/http_cookie';
$log_db = '/tmp/job_log';
$hash_db = '/tmp/http_yahoo';
$bin_grep = '/bin/grep';

$plurk_api_key = 'YOUR_PLURK_API_KEY';
$plurk_id = 'LOGIN_ID';
$plurk_passwd = 'LOGIN_PASSWORD';

if( file_exists( $log_db ) )
    return;

        $result = do_act(
            'http://www.plurk.com/API/Users/login' ,
            'POST' ,
            array(
                'api_key'       => $plurk_api_key ,
                'username'      => $plurk_id ,
                'password'      => $plurk_passwd
            ) ,
            $cookie_db
        );

$source = getNews();
foreach( $source as $data )
{
    if( !check_exists( $data['url'] ) )
    {
        $target_url = NULL;
        if( strlen( $data['url'] ) < 100 )
           $target_url = $data['url'];
        else
            $target_url = getTinyurl( $data['url'] );

        if( !empty( $target_url ) )
        {
            $plurk = '[News]'.$target_url.' ('.$data['title'].')';
            $result = do_act(
                'http://www.plurk.com/API/Timeline/plurkAdd' ,
                'POST' ,
                array(
                    'api_key'       => $plurk_api_key ,
                    'qualifier'     => 'shares' , // loves , likes , shares , ...
                    'content'       => $plurk
                ) ,
                $cookie_db
            );
        }
        put_db( $data['url'] );
    }
}
exit;

function check_exists( $url )
{
    global $hash_db , $bin_grep;
    if( !file_exists( $hash_db ) )
        return false;
    $cmd = $bin_grep.' -c "'. md5($url) .'" '.$hash_db;
    $result = shell_exec( $cmd );
    $result = trim( $result );
    //echo "[$cmd]\n[$result]\n";
    return !empty( $result );
}
function put_db( $url )
{
    global $hash_db , $log_db ;
    if( !file_exists( $hash_db ) )
        $fp = fopen( $hash_db , 'w' );
    else
        $fp = fopen( $hash_db , 'a' );
    if( $fp )
    {
        fwrite( $fp , md5($url) . "\n" );
        fclose( $fp );
    }
    else
        file_put_contents( $log_db , "Error" );
}
function getNews()
{
    global $log_db;
    $out = array();
    $raw = file_get_contents( 'http://tw.yahoo.com/' );
    $pattern = '<label>';
    $raw = stristr( $raw , $pattern );
    if( empty( $raw ) )
    {
        file_put_contents( $log_db , "Parser Error 1" );
        return $out;
    }
    $raw = substr( $raw , strlen( $pattern ) );
    $pattern = '<ol>';
    $finish = strpos( $raw , $pattern );
    if( $finish < 0 )
    {
        file_put_contents( $log_db , "Parser Error 2" );
        return $out;
    }
    $raw = substr( $raw , 0 , $finish );
    if( empty( $raw ) )
        return $out;
    $pattern = '{<h3[^>]*>[^<]*<a href="(.*?)"[^>]*>(.*?)</a></h3>}is';
    if( preg_match_all( $pattern , $raw , $matches ) )
    {
        for( $i=0 , $cnt=count( $matches[1] ) ; $i<$cnt ; ++$i )
        {
            array_push( $out , array(
                'url' => strstr( $matches[1][$i] , 'http:' ) ,
                'title' => $matches[2][$i] )
            );
        }
    }
    else
        file_put_contents( $log_db , "Parser Error 3" );
    return $out;
}
function do_act( $target_url , $type , $data , $cookie_file = NULL )
{
        $ch = curl_init();
        if( $type == 'GET' )    // GET
        {
                $target_url .= http_build_query( $data );
                curl_setopt($ch, CURLOPT_URL, $target_url );
        }
        else                    // POST
        {
                curl_setopt( $ch , CURLOPT_URL , $target_url );
                curl_setopt( $ch , CURLOPT_POST , true );
                curl_setopt( $ch , CURLOPT_POSTFIELDS , http_build_query( $data ) );
        }

        if( isset( $cookie_file ) )     // cookie
        {
                curl_setopt( $ch , CURLOPT_COOKIEFILE , $cookie_file );
                curl_setopt( $ch , CURLOPT_COOKIEJAR , $cookie_file );
        }

        curl_setopt( $ch , CURLOPT_RETURNTRANSFER , true );
        //curl_setopt( $ch , CURLOPT_FOLLOWLOCATION , true );
        //curl_setopt( $ch , CURLOPT_SSL_VERIFYPEER , false );

        $result = curl_exec( $ch );
        curl_close( $ch );
        return $result;
}
function getTinyurl( $url )
{
        $new_url = @file_get_contents( 'http://tinyurl.com/api-create.php?url='.urlencode($url) );
        $new_url = trim( $new_url );
        if( !empty( $new_url ) )
            return $new_url;
        return NULL;
}
?>


6 則留言:

  1. 你好,我想請問一下,我是使用java來寫,可是java沒有類似Unix 的 Crontab 運作
    所以,如果我是用java寫出一個和plurk溝通的程式
    我要如何使他持續運作呢??

    版主回覆:(02/18/2011 06:42:42 AM)


    你運行程式的環境是在 Windows 還是 Unix 呢?若是 Unix 的話,那應該都有 crontab 可以用的,因此,只要是指令運行的動作都可以交給 crontab 來管理,例如每小時執行一次等。

    倘若你是在 Windows 的話,那就要去使用"排程工作"來幫你自動執行啦,所以你可能有些誤會囉!無論 Unix 的 crontab 或是 Windows 的排程工作,都是作業系統提供的服務,它們可以幫你在指定的時間下運行程式。

    回覆刪除
  2. 先感謝你這麼快回我~~~

    我是使用Windows 作業系統,可以請你告訴我,要如何使用"排程工作"來自動執行嗎?
    我對作業系統的部分不熟悉,所以,可能要請你從基本的地方來解說,感謝你了!!

    版主回覆:(01/08/2010 04:57:33 PM)


    你可以看看這篇教學:

    Windows XP 排定的工作 - 在 Windows 自動定時執行程式
    http://blog.xuite.net/vexed/tech/22123519

    簡單來說,在上例教學的後面,你就是要去輸入類似 java your_plurk_robot 的方式,其中 your_plurk_rebot.java 就是你寫的程式,可以先從 cmd mode 下測試好再填入,另外,建議都用絕對路徑,如 "C:\Java\java.exe" ...

    若你覺得提的例子不夠多,那我剛好也有一篇有用到,只不過偏了很多

    免費網路廣播鬧鐘 - 以 Hinedo 實作
    http://changyy.pixnet.net/blog/post/24162778

    回覆刪除
  3. 太感謝你了,我會好好研究的....感謝你解決了我的疑惑~~

    版主回覆:(01/09/2010 02:42:47 AM)


    祝你一切順利啦 :D

    回覆刪除
  4. Java 有 TimerTask 可以使用,這樣就不用理會平台是什麼了。

    版主回覆:(01/09/2010 03:17:32 AM)


    感謝分享 :D 我太少用 Java 了, 但不曉得用它的意思是不是像在跑 thread , 然後某段時間 check 一下呢?我比較偏好 crontab 那種單純做一次的方式 XD 大概是不用在意效能以及少資源和方便設定的關係

    回覆刪除
  5. 請問如果是要擷取網站RSS的資料應該怎麼修改這份php?

    版主回覆:(01/19/2010 04:13:27 PM)


    首先你必須先看懂這份 code, 接著就可以只改 function getNews() 就好

    getNews() 是回傳一個 Array, 每個元素都有 title 跟 url 囉

    Array(
    [0] => ( 'title'=> '標題0' , 'url' => '網址0' ) ,
    [1] => ( 'title'=> '標題1' , 'url' => '網址1' ) ,
    ...
    )

    如此一來程式的變動最小囉

    回覆刪除
  6. 感謝版主快速的回應....^_^


    回覆刪除