Поддерживать сеанс в скребке страницы Eventlet? - PullRequest
3 голосов
/ 19 февраля 2010

Я пытаюсь очистить сайт, требующий аутентификации (не http-аутентификации). Сценарий, который я использую, основан на этом примере 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.

Используя приведенный выше код в качестве ориентира, как мне создать сеанс, который будет использовать остальная часть пула? (Мне нужно, чтобы последующие запросы делались параллельно)

Ответы [ 3 ]

4 голосов
/ 20 февраля 2010

Я ни в коем случае не эксперт в этом вопросе, но похоже, что стандартный способ поддержания состояния сеанса с помощью 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
1 голос
/ 20 февраля 2010

Как предложено ниже, используйте mechanize . Он позаботится о деталях низкого уровня, таких как управление файлами cookie для вас.

Однако, чтобы сторонняя библиотека работала с eventlet, вам нужно заменить объекты сокета и ssl из stdlib чем-то асинхронным внутри.

Это возможно в eventlet, но здесь не все так просто. Я рекомендую использовать gevent , где все, что вам нужно сделать, это

от gevent import monkey; monkey.patch_all ()

, а затем сторонние библиотеки должны просто работать.

Вот пример .

0 голосов
/ 19 февраля 2010

Вы можете использовать библиотеку mechanize , чтобы упростить установление сеанса, а затем использовать одну из различных техник многопоточности / многопроцессорной обработки, как этот рецепт пула потоков (первое обращение в Google , возможно, немного излишним, обязательно прочитайте комментарии).

...