2010-02-19 10 views
3

저는 인증이 필요한 사이트 (http auth가 아닌)의 일부 스크래핑을하려고합니다. 사용중인 스크립트는 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) 

세션 설정은 간단하지 않습니다. 로그인 페이지를로드하고 로그인 양식에서 일부 변수를 추출한 다음 auth 세부 사항 및 해당 변수와 함께 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

+1

환영합니다! 다른 Eventlet 사용자 및 개발자와 어울리고 싶다면 freenode의 IRC 채널 #eventlet을 사용하십시오. – rdw

+0

대단히 도움이되는 답변입니다. 이 코드 예제에 감사드립니다. – Profane

0

the mechanize library을 사용하면 세션을 쉽게 설정하고 threading pool recipe과 같은 다양한 스레딩/멀티 프로세싱 기술 중 하나를 사용할 수 있습니다 (Google에서 첫 번째 히트, 아마도 약간의 잔인 함 , 당신이 코멘트를 읽었는지 확인하십시오).

1

등이 mechanize을 사용하여 아래에 제안했다. 그것은 당신을위한 쿠키 관리 같은 낮은 수준의 세부 사항을 돌볼 것입니다.

그러나 이벤트 릿으로 타사 라이브러리를 작동 시키려면 stdlib의 socket 및 ssl 객체를 비동기식으로 바꾸어야합니다.

이것은 eventlet에서 수행 할 수 있지만 여기서는 그리 간단하지 않습니다. 당신이해야 할 모든 gevent 수입 원숭이에서

입니다 gevent를 사용하는 것이 좋습니다 ; monkey.patch_all()

타사 라이브러리가 작동해야합니다.

여기는 example입니다.