2011-12-26 8 views
0

編集:なぜマイナス1ですか?私がやろうとしています何学校のサイトからスケジュールデータを取得できません。 cURLでのログインは動作しません

は次のとおりです。

  • 私はカールを使用して私の学校のサイトにログインし、自分のAIのためにそれを使用するようにスケジュールをつかむしようとしています。

私はパスと番号を使用してログインする必要がありますが、学校のサイトのフォームにも非表示の「トークン」が必要です。

<form action="index.php" method="post"> 
    <input type="hidden" name="token" value="becb14a25acf2a0e697b50eae3f0f205" /> 
    <input type="text" name="user" /> 
    <input type="password" name="password" /> 
    <input type="submit" value="submit"> 
</form> 

トークンを正常に取得できました。それから私はログインしようとするが失敗する。

// Getting the whole website 
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, 'http://www.school.com'); 
$data = curl_exec($ch); 

// Retrieving the token and putting it in a POST 
$regex = '/<regexThatWorks>/'; 
preg_match($regex,$data,$match); 
$postfields = "user=<number>&password=<secret>&token=$match[1]"; 

// Should I use a fresh cURL here? 

// Setting the POST options, etc. 
curl_setopt($ch, CURLOPT_POST, 1); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields); 

// I won't use CURLOPT_RETURNTRANSFER yet, first I want to see results. 
$data = curl_exec($ch); 

curl_close($ch); 

うーん...それは動作しません...

  • それはトークンがすべてのcurl_execを変更することは可能ですか?サイトが2回目にスクリプトを認識しないため...
  • 2番目の部分に新しいcURLインスタンス(?)を作成する必要がありますか?
  • 1つの接続内でトークンを取得する別の方法はありますか?
  • Cookies?

申し訳ありませんが、私のひどい英語のために、私はオランダ語です。

+0

cUrlは、あなたがコマンドする方法を要求します。あなたのケースでは、明らかにリクエストの正しい設定を行うことができないので、失敗します。とにかく、あなたはcUrlよりもいくつかのブラウザ自動化を探しているかもしれません。 – hakre

+0

究極の目標は私のサイトにスケジュールを表示することです。なぜ私は-1 btwに値するのですか?私はcURLを理解しようとしています。 – SuperSpy

+0

cUrlは非常に良いですが、それはあなたがそれを伝えるだけです。あなたの質問では、単にページを取得するように指示しますが、ログインの仕組みやそのすべては、実際にはcUrlとは関係ありません。書かれているように、あなたはより良いブラウザ自動化を探しているかもしれません。 – hakre

答えて

1

これは私がそれを解決した方法です。問題は、おそらく '使用していないクッキー'の部分でした。 これはおそらく「醜い」コードなので、改善が歓迎されます!

// This part is for retrieving the token from the hidden field. 
// To be honest, I have no idea what the cookie lines actually do, but it works. 
$getToken= curl_init(); 
curl_setopt($getToken, CURLOPT_URL, '<schoolsite>');  // Set the link 
curl_setopt($getToken, CURLOPT_COOKIEJAR, 'cookies.txt'); // Magic 
curl_setopt($getToken, CURLOPT_COOKIEFILE, 'cookies.txt'); // Magic 
curl_setopt($getToken, CURLOPT_RETURNTRANSFER, 1);   // Return only as a string 
$data = curl_exec($token);         // Perform action 

// Close the connection if there are no errors 
if(curl_errno($token)){print curl_error($token);} 
else{curl_close($token);} 

// Use a regular expression to fetch the token 
$regex = '/name="token" value="(.*?)"/'; 
preg_match($regex,$data,$match); 

// Put the login info and the token in a post header string 
$postfield = "token=$match[1]&user=<number>&paswoord=<mine>"; 
echo($postfields); 

// This part is for logging in and getting the data. 
$site = curl_init(); 
curl_setopt($site, CURLOPT_URL, '<school site'); 
curl_setopt($site, CURLOPT_COOKIEJAR, 'cookies.txt'); // Magic 
curl_setopt($site, CURLOPT_COOKIEFILE, 'cookies.txt'); // Magic 
curl_setopt($site, CURLOPT_POST, 1);      // Use POST (not GET) 
curl_setopt($site, CURLOPT_POSTFIELDS, $postfield);  // Insert headers 
$forevil_uuh_no_GOOD_purposes = curl_exec($site);  // Output the results 

// Close connection if no errors   
if(curl_errno($site)){print curl_error($site);} 
else{curl_close($site);} 
+0

私にとって、特に良い目的の部分によく見えます;) – Nicolas78

+0

@スーパースパイ:これをより使いやすくする方法に興味があるなら、私の答えは今、少し長いですが、これはあなたが探しているものかもしれません:http://stackoverflow.com/a/8636363/367456 – hakre

1

エラーメッセージは表示されます。それとは独立に;あなたの学校のウェブサイトはリファラーヘッダーをチェックし、リクエストが(ログインしていると思われるアプリケーションから)来ていることを確認するかもしれません。

+0

エラーメッセージは表示されません。ちょうど空白のページ。学校のサイトが2度目のスクリプトを「認識」しないことはありますか?それで、それのために新しいトークンを作りますか? 1つの接続内でトークンを取得する別の方法はありますか? – SuperSpy

+2

nah私はそれがトークンだとは思わない。私は、リファラーをログインフォームのURLに設定しようとします。また、ログインフォームがセッションを開始しているかどうかを確認し、受け取った可能性のあるクッキーを送り返します。そしてもちろん、私はあなたが最良の意図だけでこれをやっていると仮定しています;) – Nicolas78

+0

最高の意図:もちろん、cURLがクッキーでどのように動作するか簡単に説明できますか? – SuperSpy

1

スクレイパーを構築するときに、独自のクラスを作成して、ドメインで必要な機能を実行することができます。あなたは、対処する必要があるものを処理する独自の要求クラスと応答クラスのセットを作成することから始めることができます。

独自のリクエストクラスを作成することで、必要に応じてカールリクエストを実装できます。独自のレスポンスクラスを作成すると、返されたHTMLへのアクセス/解析を手助けすることができます。

これは私がデモ用に作成したいくつかのクラスの簡単な使用例です:

# simple get request 
$request = new MyRequest('http://hakre.wordpress.com/'); 
$response = new MyResponse($request); 
foreach($response->xpath('//div[@id="container"]//div[contains(normalize-space(@class), " post ")]') as $node) 
{ 
    if (!$node->h2->a) continue; 
    echo $node->h2->a, "\n<", $node->h2->a['href'] ,">\n\n"; 
} 

それは私のブログの記事を返します。get要求を送信

Will Automattic join Dec 29 move away from GoDaddy day? 
<http://hakre.wordpress.com/2011/12/23/will-automattic-join-dec-29-move-away-from-godaddy-day/> 

PHP UTF-8 string Length 
<http://hakre.wordpress.com/2011/12/13/php-utf-8-string-length/> 

Title belongs into Head 
<http://hakre.wordpress.com/2011/11/02/title-belongs-into-head/> 

... 

はその後のように簡単です。パイには、xpath式(ここではSimpleXML)で簡単にアクセスできます。 XPathは、正規表現よりも簡単に文書のデータを照会できるため、フォームフィールドからトークンを選択するのに便利です。

投稿リクエストを送信することは次のものでした。ブログのログインスクリプトを作成しようとしましたが、かなりうまく機能していました。レスポンスヘッダーも解析する必要があったので、リクエストと応答クラスにいくつかのルーチンを追加しました。あなたのシナリオを考慮し

# simple post request 
$request = new MyRequest('https://example.wordpress.com/wp-login.php'); 
$postFields = array(
    'log' => 'username', 
    'pwd' => 'password', 
); 
$request->setPostFields($postFields); 
$response = new MyResponse($request->returnHeaders(1)->execute()); 
echo (string) $response; # output to view headers 

あなたも、あなたがそれらを使用しているとして、鉱山はすでにクッキーを使用して、何が必要とのより良い対処する独自のリクエストクラスを編集したい場合があります。

# input values 
$url = '<schoolsite>'; 
$user = '<number>'; 
$password = '<secret>'; 

# execute the first get request to obtain token 
$response = new MyResonse(new MyRequest($url)); 
$token = (string) $response->xpath('//input[@name="token"]/@value'); 

# execute the second login post request 
$request = new MyRequest($url); 
$postFields = array(; 
    'user' => $user, 
    'password' => $password, 
    'token' => $token 
); 
$request->setPostFields($postFields)->execute(); 

Democode as gist:だからあなたのシナリオのため、これらのクラスに基づいていくつかのコードは次のようになります。あなたがした後

class MySchoolService 
{ 
    private $url, $user, $pass; 
    private $isLoggedIn; 
    public function __construct($url, $user, $pass) 
    { 
     $this->url = $url; 
     ... 
    } 
    public function getSchedule() 
    { 
     $this->ensureLogin(); 

     # your code to obtain the schedule, e.g. in form of an array. 
     $schedule = ... 

     return $schedule; 
    } 
    private function ensureLogin($reuse = TRUE) 
    { 
     if ($reuse && $this->isLoggedIn) return; 

     # execute the first get request to obtain token 
     $response = new MyResonse(new MyRequest($this->url)); 
     $token = (string) $response->xpath('//input[@name="token"]/@value'); 

     # execute the second login post request 
     $request = new MyRequest($this->url); 
     $postFields = array(; 
      'user' => $this->user, 
      'password' => $this->password, 
      'token' => $token 
     ); 
     $request->setPostFields($postFields)->execute(); 

     $this->isLoggedIn = TRUE; 
    } 
} 

:あなたはこれをさらに改善したい場合は

、次のステップは、あなたがからスケジュールをフェッチするための使用を行う「学校のサービス」のために自分でクラスを作成することです

$school = new MySchoolService('<schoolsite>', '<number>', '<secret>'); 
$schedule = $school->getSchedule(); 

あなたの主なスクリプトは、MySchoolServiceを使用しています。きれいにあなただけの適切な設定とそれをインスタンス化する必要があり、あなたが簡単にあなたのウェブサイト内で使用することができ、あなたのMySchoolServiceクラスに要求/応答ロジックを包みました。

MySchoolServiceは、MyRequestMyResponseオブジェクトを使用して処理します。

MyRequestは、CookieなどでHTTPリクエスト(ここではcUrl)を処理します。

MyResponseは、HTTP応答の解析に少し役立ちます。

は、標準のインターネットブラウザでこれを比較します

Browser: Handles cookies and sessions, does HTTP requests and parses responses. 

MySchoolService: Handles cookies and sessions for your school, does HTTP requests and parses responses. 

ですから、今、何をしたいんスクリプト内の学校のブラウザを持っています。より多くのオプションが必要な場合は、簡単に拡張することができます。

これは役に立ちます。出発点は、同じ行のcUrlコードを何度も繰り返し書くのを防ぎ、戻り値を解析するためのより良いインターフェースを提供することでした。 MySchoolServiceは、自分のウェブサイト/アプリケーションコードで扱いやすいものになっています。

+0

あなたはコードが素晴らしいです!チュートリアルの目的には本当に良いです。ありがとうございました。私はもう1つの質問があることを覚えておいてください。:引用: '私の要求は、それが必要であることを知っているので、常にクッキーを使用します。リクエストにはいつクッキーが必要ですか?また、RuntimeExceptionは何をしますか?そして、 '__toString()' pert?これらのすべての質問... – SuperSpy

+1

リクエストがクッキーを必要とするかどうかはわかりませんが、具体的なケースでは、クッキーが必要であることがわかります。具体的なケースのためにコードが書かれているので、 'は単に[' Exception'](http://php.net/Exception)です。私は、URLを要求できない場合のように、例外を使用してエラーのケースを通知します。そして、['__toString'](http://php.net/__toString)では、この例では便利な文字列としてオブジェクトを扱うことができます。 – hakre

関連する問題