2017-12-31 116 views
0

Mit meinem Firefox-Browser logge ich mich in eine Download-Site ein und klicke auf einen der Abfrage-Buttons. Es erscheint ein kleines Fenster mit dem Namen "Opening report1.csv" und ich kann wählen, ob ich "Öffnen mit" oder "Datei speichern" wählen möchte. Ich speichere die Datei.Mit "Content-Disposition: Anhang" kann keine Webseite aufgerufen werden. Python-Anfragen verwenden

Für diese Aktion Live HTTP headers zeigt mir:

https: // myserver/ReportPage herunterladen & NAME = ALL & DATE = THISYEAR

GET/ReportPage herunterladen & NAME = ALL & DATE = THISYEAR HTTP/1.1
Host: myserver
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv: 52,0) Gecko/20100101 Firefox/52,0
Akzeptieren: text/html, application/xhtml + xml, application/xml; q = 0,9, /; q = 0,8
Accept-Sprache: en-US, en; q = 0,8, de-DE; q = ? 0,5, de; q = 0,3
Accept-Encoding: gzip, deflate, br
Referer: https: // myserver/ReportPage 4 & NAME = ALL & DATE = THISYEAR
Cookie: JSESSIONID = 88DEDBC6880571FDB0E6E4112D71B7D6
Anschluss: keep-alive
Upgrade-Unsichere-Anforderungen: 1

HTTP/1.1 200 OK
Datum: Sa, 30. Dezember 2017 22.37.40 GMT
Server: Apache-Coyote/1.1
Last-Modified: Sa 30. Dezember 2017 22.37.40 GMT
Gültig bis: Do., 1. Januar 1970 00 : 00: 00 GMT
Pragma: no-cache
Cache-Control: no-cache, no-store
Content-Disposition: attachment; Dateiname = "report1.csv"; Dateiname * = UTF-8''report1.csv
Content-Type: text/csv
Content-Length: 332.369
Keep-Alive: timeout = 5, max = 100
Connection: Keep-Alive-

Jetzt versuche ich dies mit Anfragen zu emulieren.

$ python3 
>>> import requests 
>>> from lxml import html 
>>> 
>>> s = requests.Session() 
>>> s.verify = './myserver.crt' # certificate of myserver for https 
>>> 
>>> # get the login web page to enter username and password 
... r = s.get('https://myserver') 
>>> 
>>> # Get url for logging in. It's the action-attribute in the form anywhere. 
... # We use xpath. 
... tree = html.fromstring(r.text) 
>>> loginUrl = 'https://myserver/' + list(tree.xpath("//form[@id='id4']/@action"))[0] 
>>> print(loginUrl) # it contains a session-id 
https://myserver/./;jsessionid=77EA70CB95252426439097E274286966?0-1.loginForm 
>>> 
>>> # logging in with username and password 
... r = s.post(loginUrl, data = {'username':'ingo','password':'mypassword'}) 
>>> print(r.status_code) 
200 
>>> # try to get the download file using url from Live HTTP headers 
... downloadQueryUrl = 'https://myserver/ReportPage?download&NAME=ALL&DATE=THISYEAR' 
>>> r = s.get(downloadQueryUrl) 
>>> print(r.status_code) 
200 
>>> print(r. headers) 
{'Connection': 'Keep-Alive', 
'Date': 'Sun, 31 Dec 2017 14:46:03 GMT', 
'Cache-Control': 'no-cache, no-store', 
'Keep-Alive': 'timeout=5, max=94', 
'Transfer-Encoding': 'chunked', 
'Expires': 'Thu, 01 Jan 1970 00:00:00 GMT', 
'Pragma': 'no-cache', 
'Content-Encoding': 'gzip', 
'Content-Type': 'text/html;charset=UTF-8', 
'Server': 'Apache-Coyote/1.1', 
'Vary': 'Accept-Encoding'} 
>>> print(r.url) 
https://myserver/ReportPage?4&NAME=ALL&DATE=THISYEAR 
>>> 

Die Anfrage ist erfolgreich, aber ich bekomme die Datei Download-Seite nicht. Es gibt keine "Content-Disposition: Attachment"; Eintrag in der Kopfzeile. Ich bekomme nur die Seite, von der die Abfrage startet, z. die Seite vom Referer.

Hat das etwas mit dem Session-Cookie zu tun? Scheint Anfragen verwaltet dies automatisch. Gibt es eine spezielle Handhabung für CSV-Dateien? Muss ich Streams verwenden? Ist die von Live HTTP Headers angezeigte Download-URL die richtige? Vielleicht gibt es eine dynamische Schöpfung?

Wie bekomme ich eine Webseite mit "Content-Disposition: Anhang;" von myserver und lade seine Datei mit Anfragen herunter?

+0

vielleicht müssen Sie einige Header hinzufügen, um anzufragen - dh. "User-Agent" – furas

+0

hast du 'r.text' überprüft? Vielleicht gibt es nützliche Inforamtion - dh. es kann eine Warnmeldung sein. Sie könnten es in eine Datei schreiben und diese Datei im Browser öffnen. – furas

+0

@furas danke für das Zeigen. Ich werde mir das anschauen und es versuchen. – Ingo

Antwort

0

Ich verstehe es. @Patrick Mevzek weist mich in die richtige Richtung. Danke dafür.

Nach dem Login Ich bleibe nicht auf der ersten Seite in protokolliert und die Abfrage aufrufen. Stattdessen fordere ich die Berichtsseite an, extrahiere die Abfrage-URL von ihr und frage die Abfrage-URL an. Jetzt bekomme ich die Antwort mit "Content-Disposition: attachment" in der Kopfzeile. Es ist jetzt einfach, den Text auf Standard auszudrucken. Ich bevorzuge das, weil ich die Ausgabe zu jeder Datei umleiten kann. Info-Nachrichten gehen zu stderr, damit sie die umgeleitete Ausgabe nicht durcheinander bringen. Ein typischer Anruf ist ./download >out.csv.

Der Vollständigkeit halber ist hier die Skriptvorlage ohne Fehlerprüfung seiner Arbeits zu klären.

#!/usr/bin/python3 

import requests 
import sys 
from lxml import html 

s = requests.Session() 
s.verify = './myserver.crt' # certificate of myserver for https 

# get the login web site to enter username and password 
r = s.get('https://myserver') 

# Get url for logging in. It's the action-attribute in the form anywhere. 
# We use xpath. 
tree = html.fromstring(r.text) 
loginUrl = 'https://myserver/' + tree.xpath("//form[@id='id4']/@action")[0] 

# logging in with username and password and go to ReportPage with queries 
r = s.post(loginUrl, data = {'username':'ingo','password':'mypassword'}) 
queryUrl = 'https://myserver/ReportPage?NAME=ALL&DATE=THISYEAR' 
r = s.get(queryUrl) 

# Get the download link for this query from this site. It's a link anywhere 
# with value 'Download (UTF8)' 
tree = html.fromstring(r.text) 
downloadUrl = 'https://myserver/' + tree.xpath("//a[.='Download (UTF8)']/@href")[0] 

# get the download file 
r = s.get(downloadUrl) 
if r.headers.get('Content-Disposition'): 
    print('Downloading ...', file=sys.stderr) 
    print(r.text) 

# log out 
r = s.get('https://myserver/logout') 
Verwandte Themen