Cześć.
Piszę program, w którym potrzebuję danych ze strony internetowej. Trzeba się do niej zalogować i sprawdzać ciasteczko. Chcę to robić przez basha, dokładniej wgeta, choć jeśli coś nadaje się do tego lepiej, to chętnie spróbuję. Problem polega na tym, że nie mogę się zalogować, pobrana strona wyświetla, że sesja wygasła. W kodzie strony zauważyłem coś takiego jak WebSessionToken, czy to może mieć jakieś znaczenie? I jak to obsłużyć?
Będę wdzięczny za wszelką pomoc!
Napisz to w pythonie. Pewnie mają csrf token i musisz najpierw wejść na stronę logowania, zapamiętać sobie token z cookie a potem dopiero wysłać posta z logowaniem.
Dzięki za odpowiedź. Powiesz jakich narzędzi dokładniej użyć, żeby wiedzieć, czego szukać? Pythona jeszcze nie znam, tylko C/C++, ale miałem w planach, więc akurat jest okazja. Jakieś linki również mile widziane.
Hasło: python fill login form
Odpowiedź: http://www.blog.pythonlibrary.org/2012/06/08/python-101-how-to-submit-a-web-form/
@vpiotr ale o csrf nie wspominają ;) To będzie coś w stylu:
cookies = {}
url_login = 'http://a.bc/login'
login_request = requests.get(url_login, cookies=cookies)
login_page = login_request.text
csrf = "<input type='hidden' name='csrftoken' value='" # albo jak to na stronie się u ciebie pojawia
start = login_page.find(csrf) + len(csrf)
token = login_page[start:start+32]
cookies['csrftoken'] = token # albo jak sie u ciebie to cookie nazywa
url_post = 'http://a.bc/login'
resp = requests.post(url_post, data={'login': 'login', 'password':'password', 'csrftoken': token}, cookies=cookies)
result_page_content = resp.text
Co dokładnie robi ta linijka token = text[start:start+32]? Wydaje mi się, że powinna wyrzucić 32 znaki zmiennej start, ale w ogóle jak wypisze start, to jest to jakby int, a nie string. A w tej linijce 'nie znajduje' mi 'text', więc jakbyś mógł to trochę opisać. Przepraszam za głupie pytania, ale jak mówiłem, do pythona dopiero przysiadam.
A tam to jakaś głupio zahardkodowana długość tego tokena ;] W tej zmiennej start powinien być jakiś hex-string a potem pewnie domknięcie tagu itd, a my chcemy wyciąć tylko ten hex string. Poprawiłem też ten kod bo pisałem z palca i dałem dwie różne nazwy ;] text
to mialo być oczywiście login_page
Teraz działa i Token już elegancko wydobywam, ale dalej coś nie idzie. "Sesja wygasła". Formularz ze strony wygląda tak:
<form method="post" action="/EdukacjaWeb/logInUser.do"><input type="hidden" name="cl.edu.web.TOKEN" value="FMTQ2NjM2OTMzNDAyNA==">
<tr>
<td align="center"><INPUT TYPE="text" name="login" value="" maxlength="50" size="30" CLASS="UZYTKOWNIK">
</td>
</tr>
<tr>
<td CLASS="INFO" valign="middle" height="20"> Hasło:
</td>
</tr>
<tr>
<td align="center"><INPUT TYPE="password" name="password" value="" maxlength="20" size="30" CLASS="HASLO">
</td>
</tr>
<tr>
<td align="center"><input type="submit" value=" " CLASS="BUTTON_ZALOGUJ" title="Zaloguj">
</td>
</tr>
<tr>
<td align="center"><input type="submit" onClick="form.action='remindPassword.do'" CLASS="BUTTON_ZAPOMNIALEM" title="Zapomniałem hasła" value=" ">
</td>
</tr>
</form>
Coś jeszcze powinienem uwzględnić w skrypcie? Nazwy pól i csrf oczywiście odpowiednio zmieniłem.
#!/usr/bin/env python
import requests
with requests.Session() as c:
cookies = {}
url_login = 'https://edukacja.pwr.wroc.pl/EdukacjaWeb/studia.do'
login_request = requests.get(url_login, cookies=cookies)
login_page = login_request.text
csrf = "cl.edu.web.TOKEN"
start = login_page.find(csrf) + len(csrf)
token = login_page[start+9:start+30]
cookies['cl.edu.web.TOKEN'] = token
url_post = 'https://edukacja.pwr.wroc.pl/EdukacjaWeb/studia.do'
resp = requests.post(url_post, data={'login': 'moj_login', 'password': 'moje_haslo', 'cl.edu.web.TOKEN': token}, cookies=cookies)
result_page_content = resp.text
print result_page_content
Z tego co widzę to url na posta powinien być https://edukacja.pwr.wroc.pl/EdukacjaWeb/logInUser.do
Wtedy też jest taki błąd. Przy użyciu tego adresu to nawet jak ręcznie wklepię go w przeglądarkę, to jest błąd.
Właściwie to ten błąd jest tylko przy tym adresie. Przy tym, co podałem wyżej, to po prostu jest zwykła strona z formularzem do logowania.
Ach jasne, bo zapomniałem że jest jeszcze sessionid cookie ;] Spróbuj czegoś takiego:
#!/usr/bin/env python
import requests
with requests.Session() as c:
url_login = 'https://edukacja.pwr.wroc.pl/EdukacjaWeb/studia.do'
login_request = requests.get(url_login)
login_page = login_request.text
csrf = "cl.edu.web.TOKEN"
start = login_page.find(csrf) + len(csrf)
token = login_page[start+9:start+30]
cookies = login_request.cookies
cookies['cl.edu.web.TOKEN'] = token
url_post = 'https://edukacja.pwr.wroc.pl/EdukacjaWeb/logInUser.do'
resp = requests.post(url_post, data={'login': 'moj_login', 'password': 'moje_haslo', 'cl.edu.web.TOKEN': token}, cookies=cookies)
result_page_content = resp.text
print result_page_content
WOW! Działa, nie spodziewałem się, że tak szybko pójdzie. Mógłbyś jeszcze powiedzieć, o ile się da, jak "wyeksportować" ciastko.
Tzn które ciastko chcesz eksportować? Ciastka masz w mapie cookies
z requestu (tak jak zawartość strony masz w polu text
) więc możesz je sobie odczytać jak chcesz.
Dobra, dałem radę. Bardzo dziękuję za pomoc. Temat do zamknięcia.
Shalom napisał(a):
Ach jasne, bo zapomniałem że jest jeszcze sessionid cookie ;] Spróbuj czegoś takiego:
#!/usr/bin/env python import requests with requests.Session() as c: url_login = 'https://edukacja.pwr.wroc.pl/EdukacjaWeb/studia.do' login_request = requests.get(url_login) login_page = login_request.text csrf = "cl.edu.web.TOKEN" start = login_page.find(csrf) + len(csrf) token = login_page[start+9:start+30] cookies = login_request.cookies cookies['cl.edu.web.TOKEN'] = token url_post = 'https://edukacja.pwr.wroc.pl/EdukacjaWeb/logInUser.do' resp = requests.post(url_post, data={'login': 'moj_login', 'password': 'moje_haslo', 'cl.edu.web.TOKEN': token}, cookies=cookies) result_page_content = resp.text
Jeśli chciałbym mieć dostęp do innej podstrony np. do ocen dodaję taki kod
url='https://edukacja.pwr.wroc.pl/EdukacjaWeb/ocenySluchacza.do?clEduWebSESSIONTOKEN=SMTQ4NzM4NjUxOTg1Mw==&event=WyborSluchacza'
next_url = requests.get(url).text
print(ind)
Jednak w tym momencie sesja wygasła. Z tego co czytałem ("Excellent news — thanks to urllib3, keep-alive is 100% automatic within a session! Any requests that you make within a session will automatically reuse the appropriate connection!") nie powinno tak być. Co można zrobić by to naprawić i móc pobrać zawartość innej podstrony?
Możesz utworzyć sobie gdzieś na początku x = requests.Session()
a potem zamiast requests.get(url_login)
robić x.get(url_login)
i będziesz wtedy używał tej samej sesji.
Próbowałem, ale to nie robiło żadnej różnicy. Znalazłem błąd i okazał się bardzo banalny. Adres podstrony, której źródło chciałem pobrać zmieniał się w zależności od tokena csrf. Prosta podmiana i wszystko działa :)