2010-02-19 82 views
3

我試圖做一些需要身份驗證的網站(不是http身份驗證)。我正在使用的腳本基於this eventlet example。基本上,在Eventlet頁面刮板中維護會話嗎?

urls = ["https://mysecuresite.com/data.aspx?itemid=blah1", 
    "https://mysecuresite.com/data.aspx?itemid=blah2", 
    "https://mysecuresite.com/data.aspx?itemid=blah3"] 

import eventlet 
from eventlet.green import urllib2 

def fetch(url): 
    print "opening", url 
    body = urllib2.urlopen(url).read() 
    print "done with", url 
    return url, body 

pool = eventlet.GreenPool(10) 
for url, body in pool.imap(fetch, urls): 
    print "got body from", url, "of length", len(body) 

建立會話並不簡單,我必須加載登錄頁面,從登錄表單中提取一些變量,然後發送POST請求,其中包含身份驗證詳細信息和這些變量。會話結束後,其餘請求都是簡單的GET請求。

使用上面的代碼作爲參考點,我將如何創建池的其餘部分將使用的會話? (我需要並行進行後續請求)

回答

4

我不是這方面的專家,但它看起來像使用urllib2維護會話狀態的標準方法是爲每個會話創建一個自定義開啓器實例。這看起來是這樣的:

opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) 

然後你使用它揭幕戰你有沒有到任何身份驗證,所有的會話狀態將保持首戰對象本身。然後你可以傳遞opener對象作爲並行請求的參數。

以下是一個示例腳本,它並行地登錄到secondlife.com併爲多個用戶提供服務,併爲每個用戶並行提供多個頁面請求。此特定站點的登錄過程非常棘手,因爲它涉及從第一個請求中捕獲CSRF令牌,然後才能夠使用第二個請求登錄。出於這個原因,登錄方法非常混亂。原則應該是相同的,但是,不管是什麼網站,你有興趣。

import eventlet 
from eventlet.green import urllib2 
import re 

login_url = 'https://secure-web28.secondlife.com/my/account/login.php?lang=en&type=second-life-member&nextpage=/my/index.php?lang=en' 

pool = eventlet.GreenPool(10) 

def fetch_title(opener, url): 
    match = re.search(r'<title>(.*)</title>', opener.open(url).read()) 
    if match: 
     return match.group(1) 
    else: 
     return "no title" 

def login(login_url, fullname, password): 
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) 
    login_page = opener.open(login_url).read() 
    csrf_token = re.search(r'<input type="hidden" name="CSRFToken" value="(.*)"/>', login_page).group(1) 
    username, lastname = fullname.split() 
    auth = "CSRFToken=%s&form[type]=second-life-member&form[nextpage]=/my/index.php?lang=en&form[persistent]=Y&form[form_action]=Log%%20In&form[form_lang]=en&form[username]=%s&form[lastname]=%s&form[password]=%s&submit=Submit" % (
     csrf_token, username, lastname, password) 
    logged_in = opener.open(login_url, auth).read() 
    return opener 


def login_and_fetch(login_url, fullname, password, page_urls): 
    opener = login(login_url, fullname, password) 
    # note that this deliberately uses the global pool 
    pile = eventlet.GreenPile(pool) 
    for url in page_urls: 
     pile.spawn(fetch_title, opener, url) 

    return pile 

login_urls = [login_url] *2 
usernames = [...] 
passwords = [...] 
page_urls = [['https://secure-web28.secondlife.com/my/account/?lang=en-US', 
     'https://secure-web28.secondlife.com/my/community/events/index.php?lang=en-US']] * 2 

for user_iter in pool.imap(login_and_fetch, login_urls, usernames, passwords, page_urls): 
    for title in user_iter: 
     print "got title", title 
+0

這就是我一直在尋找的東西,一直到棘手的登錄位。萬分感謝。 – kbanman 2010-02-20 19:28:18

+1

歡迎!如果您想與其他Eventlet用戶和開發者聊天,請隨時在freenode上通過IRC頻道#eventlet進行投票。 – rdw 2010-02-21 18:47:32

+0

極有幫助的迴應;感謝這個代碼示例 – Profane 2011-08-23 12:38:09

0

您可以使用the mechanize library使會話建立更容易,然後使用其中一種不同的線程/多處理技術,如threading pool recipe(首先在Google上打,可能有點矯枉過正,請確保你閱讀了評論)。

1

像下面的建議,使用mechanize。它會照顧低級別的細節,比如cookie的管理。

但是,要使第三方庫適用於eventlet,您需要將stdlib中的套接字和ssl對象替換爲異步引導下的某些對象。

這是可以在eventlet中實現的,但在這裏並不是非常簡單。 我推薦使用gevent,你所要做的就是

from gevent import monkey; monkey.patch_all()

然後第三方庫應該只是工作。

這是example