2017-01-31 10 views
0

以下は、Cookの公式ウェブサイト(https://www.cooksillustrated.com/sign_in)へのログインに使用しようとしているコードです。Pythonデータスクラップ - フォーム認証の問題

セッションを開始し、認証トークンと隠れたエンコードフィールドを取得し、電子メールとパスワードフィールドの「名前」と「値」を渡します(chromeの要素を調べることで見つけられます)。フォームに他の要素が含まれていないようです。しかし、postメソッドは私をログインさせません。

CSRFトークンのすべてが "=="で終わっていることに気がつきましたので、削除しようとしました。しかし、それは動作しませんでした。

"名前"の代わりにフォーム入力の "id"フィールドを使用するようにポストを修正しようとしました(暗闇の中のちょうどショット...名前は私のものから動作するはずです他の例に見られる)。

ご意見をいただければ幸いです。

import requests, lxml.html 
s = requests.session() 

# go to the login page and get its text 
login = s.get('https://www.cooksillustrated.com/sign_in') 
login_html = lxml.html.fromstring(login.text) 

# find the hidden fields names and values; store in a dictionary 
hidden_inputs = login_html.xpath(r'//form//input[@type="hidden"]') 
form = {x.attrib['name']: x.attrib['value'] for x in hidden_inputs} 
print(form) 

# I noticed that they all ended in two = signs, so I tried taking that off 
# form['authenticity_token'] = form['authenticity_token'][:-2] 

# this adds to the form payload the two named fields for user name and  password 
# found using the "inspect elements" on the login screen 
form['user[email]'] = 'my_email' 
form['user[password]'] = 'my_pw' 

# this uses "id" instead of "name" from the input fields 
#form['user_email'] = 'my_email' 
#form['user_password'] = 'my_pw' 

response = s.post('https://www.cooksillustrated.com/sign_in', data=form) 
print(form) 

# trying to see if it worked - but the response URL is login again instead of main page 
# and it can't find my name 
# responses are okay, but I think that just means it posted the form 
print(response.url) 
print('Christopher' in response.text) 
print(response.status_code) 
print(response.ok) 
+0

CSRFトークンの末尾にある「==」は、Base64文字列であるため、[padding](https://en.wikipedia.org/wiki/Base64#Output_Padding)です。 – Adrian

+0

ありがとうございます。デコードや削除が必要なのでしょうか?それとも、「そのまま」合格するのでしょうか? –

+0

CSRFは** C ** ross - ** S ** ite ** R ** equest ** F ** orgeryの略で、悪意のあるサイト、電子メール、プログラムなどによってユーザーのブラウザが不要な操作を実行します。トークンは、これを防ぐ手段です。そのまま渡す必要があります。 – Adrian

答えて

0

まあ、POSTリクエストURLはhttps://www.cooksillustrated.com/sessionsであるべきであり、ログインしているときは、すべてのトラフィックをキャプチャする場合は、サーバーに対して行われた実際のPOSTリクエストを見つけることができます:

POST /sessions HTTP/1.1 
Host: www.cooksillustrated.com 
Connection: keep-alive 
Content-Length: 179 
Cache-Control: max-age=0 
Origin: https://www.cooksillustrated.com 
Upgrade-Insecure-Requests: 1 
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 
Content-Type: application/x-www-form-urlencoded 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 
Referer: https://www.cooksillustrated.com/sign_in 
Accept-Encoding: gzip, deflate, br 
Accept-Language: en-US,en;q=0.8 

utf8=%E2%9C%93&authenticity_token=Uvku64N8V2dq8z%2BGerrqWNobn03Ydjvz8xqgOAvfBmvDM%2B71xJWl2DmRU4zbBE15gGVESmDKP2E16KIqBeAJ0g%3D%3D&user%5Bemail%5D=demo&user%5Bpassword%5D=demodemo 

ていることに注意してください最後の行はこのリクエストのエンコードされたデータです。utfauthenticity_tokenuser[email]user[password]の4つのパラメータがあります。

だからあなたの場合には、formは、それらのすべてを含める必要があります。

form = {'user[email]': 'my_email', 
     'user[password]': 'my_pw', 
     'utf': '✓', 
     'authenticity_token': 'xxxxxx' # make sure you don't ignore '==' 
} 

をまた、あなたは、クロム(または任意のブラウザあなたが好き)から来るとして表示されるように、いくつかのヘッダを追加したい場合があり、デフォルトのヘッダー以来requestpython-requests/2.13.0で、いくつかのウェブサイトは、「ボット」からのトラフィックを好きではない:

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36', 
      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 
      'Accept-Encoding': 'gzip, deflate, br', 
      ... # more 
} 

は、今、私たちは、POSTリクエストを作成する準備が整いました

response = s.post('https://www.cooksillustrated.com/sessions', data=form, headers=headers) 
+0

ありがとう!ポスト機能を/ sessions URLに変更すると完全に動作しました。ヘッダーを変更する必要はありませんでしたが、問題を回避するために追加します。 シェーンのヘッダーとフォームの情報がどこから来たのか不思議な人には、「インスペクト」>「ネットワーク」>「フォーム名を左から選択する」>「ヘッダー」に移動します。 「フィルタ」ボックスはヘッダーテキストには表示されませんが、比較的簡単に最新の操作を見つけることができます。 –