Próbuję zalogować się do witryny jednocześnie, używając wielu poświadczeń z aiohttp
i asyncio
. W funkcji create_tasks
generuję listę sesji, które będą używane dla każdego z nich. Powodem, dla którego nie mogę po prostu utworzyć sesji w ramach funkcji login
jest to, że ten sam obiekt sesji będzie używany w całym kodzie. Próbuję stworzyć sposób, w jaki mogę użyć menedżera kontekstu do obsługi zamykania sesji (aby uniknąć błędów środowiska wykonawczego, pozostawiając je otwarte).Jak zmienić ten kod, aby używać menedżerów kontekstów?
Następujący kod działa zgodnie z przeznaczeniem (równoczesne gromadzenie strony logowania i analizowanie tokenu w puli procesowej), ale generuje sesje oddzielnie od zadań i wymaga ich zamknięcia na końcu.
from bs4 import BeautifulSoup
from concurrent.futures import ProcessPoolExecutor
import aiohttp
import asyncio
#TODO: make this safe, handle exceptions
LOGIN_URL = "http://example.com/login"
CLIENT_CNT = 10
proc_pool = ProcessPoolExecutor(CLIENT_CNT)
def get_key(text):
soup = BeautifulSoup(text, "html.parser")
form = soup.find("form")
key = form.find("input", attrs={"type": "hidden", "name": "authenticityToken"})
return key.get("value", None)
async def login(username:str, password:str, session:aiohttp.ClientSession, sem:asyncio.BoundedSemaphore, loop:asyncio.AbstractEventLoop=None):
loop = loop or asyncio.get_event_loop()
async with sem:
async with session.get(LOGIN_URL) as resp:
x = await asyncio.ensure_future(loop.run_in_executor(proc_pool, get_key, await resp.text()))
print(x)
def create_tasks(usernames, passwords, sem:asyncio.BoundedSemaphore, loop:asyncio.AbstractEventLoop=None):
loop = loop or asyncio.get_event_loop()
tasks = []
sessions = []
for u, p in zip(usernames, passwords):
session = aiohttp.ClientSession(loop=loop)
sessions.append(session)
tasks.append(login(u, p, session, sem, loop))
return tasks, sessions
if __name__ == "__main__":
loop = asyncio.get_event_loop()
sem = asyncio.BoundedSemaphore(CLIENT_CNT)
usernames = ("a", "b", "c", "d", "e", "f", "g")
passwords = ("a", "b", "c", "d", "e", "f", "g")
tasks, sessions = create_tasks(usernames, passwords, sem, loop)
loop.run_until_complete(asyncio.gather(*tasks, loop=loop))
for session in sessions:
session.close()
ja poprzednio wykonane create_tasks
się współprogram napisał klasy otoki, aby iterables async i próbuje za pomocą
async with aiohttp.ClientSession() as session:
tasks.append(login(u, p, session, sem, loop)
Ale jak się obawiałem, to powiedział, że sesja została już zamknięta przez czas został uruchomiony.
nie powinien "def create_tasks()' być 'async def create_tasks()'? – Juggernaut
To było, gdy użyłem asynchronicznego menedżera kontekstów dla każdej sesji, ale zmieniłem to ponieważ ta metoda nie działała i 'asynchroniczna def' była niepotrzebna. – Goodies
Dlaczego zadanie nie może utworzyć sesji, wykonać proces logowania (uzyskanie pliku cookie, tokenu itd.) I samemu zamknąć sesję? Nie rozumiem, dlaczego sesja, a nie sesja _factory_, taka jak 'aiohttp.ClientSession', powinna zostać przypisana do zadania. – 9000