2012-07-17 8 views
7

Sto scrivendo un parser Google Scholar e in base a this answer, sto impostando i cookie prima di afferrare l'HTML. Questo è il contenuto del mio file di cookies.txt:Perché Python dice che questo file cookie di Netscape non è valido?

# Netscape HTTP Cookie File 
# http://curlm.haxx.se/rfc/cookie_spec.html 
# This file was generated by libcurl! Edit at your own risk. 

.scholar.google.com  TRUE /  FALSE 2147483647  GSP  ID=353e8f974d766dcd:CF=2 
.google.com  TRUE /  FALSE 1317124758  PREF ID=353e8f974d766dcd:TM=1254052758:LM=1254052758:S=_biVh02e4scrJT1H 
.scholar.google.co.uk TRUE /  FALSE 2147483647  GSP  ID=f3f18b3b5a7c2647:CF=2 
.google.co.uk TRUE /  FALSE 1317125123  PREF ID=f3f18b3b5a7c2647:TM=1254053123:LM=1254053123:S=UqjRcTObh7_sARkN 

e questo è il codice che sto usando per afferrare il codice HTML:

import http.cookiejar 
import urllib.request, urllib.parse, urllib.error 

def get_page(url, headers="", params=""): 
    filename = "cookies.txt" 
    request = urllib.request.Request(url, None, headers, params) 
    cookies = http.cookiejar.MozillaCookieJar(filename, None, None) 
    cookies.load() 
    cookie_handler = urllib.request.HTTPCookieProcessor(cookies) 
    redirect_handler = urllib.request.HTTPRedirectHandler() 
    opener = urllib.request.build_opener(redirect_handler,cookie_handler) 
    response = opener.open(request) 
    return response 

start = 0 
search = "Ricardo Altamirano" 
results_per_fetch = 20 
host = "http://scholar.google.com" 
base_url = "/scholar" 
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; U; ru; rv:5.0.1.6) Gecko/20110501 Firefox/5.0.1 Firefox/5.0.1'} 
params = urllib.parse.urlencode({'start' : start, 
           'q': '"' + search + '"', 
           'btnG' : "", 
           'hl' : 'en', 
           'num': results_per_fetch, 
           'as_sdt' : '1,14'}) 

url = base_url + "?" + params 
resp = get_page(host + url, headers, params) 

Il traceback completo è:

Traceback (most recent call last): 
    File "C:/Users/ricardo/Desktop/Google-Scholar/BibTex/test.py", line 29, in <module> 
    resp = get_page(host + url, headers, params) 
    File "C:/Users/ricardo/Desktop/Google-Scholar/BibTex/test.py", line 8, in get_page 
    cookies.load() 
    File "C:\Python32\lib\http\cookiejar.py", line 1767, in load 
    self._really_load(f, filename, ignore_discard, ignore_expires) 
    File "C:\Python32\lib\http\cookiejar.py", line 1997, in _really_load 
    filename) 
http.cookiejar.LoadError: 'cookies.txt' does not look like a Netscape format cookies file 

I Ho cercato la documentazione sul formato di file cookie di Netscape, ma non riesco a trovare nulla che mi mostri il problema. Ci sono newline che devono essere incluse? Ho cambiato le terminazioni di linea in stile Unix, per ogni evenienza, ma questo non ha risolto il problema. La specifica più vicina che riesco a trovare è this, che non mi indica nulla che mi manchi. I campi su ognuna delle ultime quattro righe sono separati da tabulazioni, non da spazi e tutto il resto mi sembra corretto.

+0

[specifica del cookie netscape] (http://curl.haxx.se/rfc/cookie_spec.html) che era ospitato su netscape.com prima che qualcuno (AOL?) Rovinasse la storia. – n611x007

+0

una specifica aggiornata come [rfc2965] (http://tools.ietf.org/html/rfc2965.html) con * Set-Cookie2 * – n611x007

+0

Per chiunque sia interessato, in realtà si può fare 'cookies.save (cookie_file, ignore_discard = True , ignore_expires = True) 'per creare un file cookie valido come istanza da confrontare con cookie.txt non validi. Line by line o bye by byte per confrontare e rimuovere la riga una per una, alla fine avresti trovato il motivo. –

risposta

10

Non vedo nulla nel codice di esempio o nella copia del file cookies.txt che è ovviamente sbagliato.

Ho controllato il codice sorgente per lo MozillaCookieJar._really_load method, che genera l'eccezione che si vede.

La prima cosa che questo metodo fa è leggere la prima riga del file specificato (usando f.readline()) e usare re.search per cercare il modello di espressione regolare "#(Netscape)? HTTP Cookie File". Questo è ciò che fallisce per il tuo file.

Sicuramente sembra come il tuo cookies.txt corrisponde a tale formato, quindi l'errore che si vede è abbastanza sorprendente.

Si noti che il file è stato aperto con un semplice open(filename) call in precedenza, quindi verrà aperto in modalità testo con supporto di fine linea universale, il che significa che non è importante che si sta eseguendo su Windows. Il codice vedrà \n stringhe terminate a capo nuovo, indipendentemente da quale convenzione newline è stata utilizzata nel file stesso.

Quello che farei in questo caso è triplo controllo che la prima riga del file è veramente corretta. Deve contenere "# Cookie Cookie HTTP" o "# Cookie Netscape HTTP" (solo spazi, nessuna tabulazione, tra le parole, corrispondenza di maiuscole/minuscole). Prova questo con il prompt di pitone:

>>> f = open('cookies.txt') 
>>> line = f.readline() 
>>> line 
'# Netscape HTTP Cookie File\n' 
>>> import re 
>>> re.search("#(Netscape)? HTTP Cookie File", line) 
<_sre.SRE_Match object at 0x10fecfdc8> 

Python eco la rappresentazione linea di fondo per me quando ho digitato line al prompt, compreso il carattere di nuova riga \n. Eventuali sorprese come i caratteri di tabulazione o gli spazi unicode a larghezza zero verranno visualizzati come codici di escape. Ho anche verificato che le espressioni regolari utilizzate dal codice cookiejar corrispondano.

È inoltre possibile utilizzare il pdb python debugger per verificare quello che il modulo http.cookiejar fa davvero:

>>> import pdb 
>>> import http.cookiejar 
>>> jar = http.cookiejar.MozillaCookieJar('cookies.txt') 
>>> pdb.run('jar.load()') 
> <string>(1)<module>() 
(Pdb) s 
--Call-- 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1759)load() 
-> def load(self, filename=None, ignore_discard=False, ignore_expires=False): 
(Pdb) s 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1761)load() 
-> if filename is None: 
(Pdb) s 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1762)load() 
-> if self.filename is not None: filename = self.filename 
(Pdb) s 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1765)load() 
-> f = open(filename) 
(Pdb) n 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1766)load() 
-> try: 
(Pdb) 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1767)load() 
-> self._really_load(f, filename, ignore_discard, ignore_expires) 
(Pdb) s 
--Call-- 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1989)_really_load() 
-> def _really_load(self, f, filename, ignore_discard, ignore_expires): 
(Pdb) s 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1990)_really_load() 
-> now = time.time() 
(Pdb) n 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1992)_really_load() 
-> magic = f.readline() 
(Pdb) 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1993)_really_load() 
-> if not self.magic_re.search(magic): 
(Pdb) 
> /opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/http/cookiejar.py(1999)_really_load() 
-> try: 

Nella sessione del campione PPB sopra ho usato una combinazione dei comandi step e next per verificare che il test di espressione regolare (self.magic_re.search(magic)) effettivamente passato.

+0

Ottima risposta! (e un buon esempio di debug di python). Non so se qualcos'altro è cambiato nel mio sistema, ma il codice funziona al momento senza alcuna modifica a 'cookies.txt' La prima riga del file era identica alla tua, inclusi spazi, schede, ecc. Quindi io non sono sicuro di quale problema abbia causato il problema. –

+0

@RicardoAltamirano solo un'ipotesi: un cambio di codifica del testo, ad es. BOM come il non ufficiale utf-8 '\ xef \ xbb \ xbf' potrebbe causare tale effetto e potrebbe non essere molto ovvio dato che solo i contenuti binari sono cambiati ma come testo potrebbe apparire lo stesso. La stessa idea potrebbe cambiare in codice se in precedenza hai usato 'open' e in seguito' codecs.open'. – n611x007

+0

@naxa: la sessione 'open()' e 'f.readline()' che mostro nella mia risposta sarebbe (su Python 2), mostra facilmente tali codepoint. IIRC a UTOM-8 BOM farebbe ancora parte del valore Unicode restituito da un oggetto file 'codecs.open()' o 'io.open()', e il letterale 'u'' letterale stringa Unicode sarebbe un gadget morto in ogni caso. –

2

A partire dal mio scenario, due modifiche sono necessarie per il MozillaCookieJar sotto (/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/)

  1. L'intestazione magica

    È possibile rimuovere la logica di controllo o aggiungere tale intestazione magica che preferisco

    '# Netscape HTTP Cookie file

  2. Il nuovo formato di file sembra consentono di omettere la scadenza

    vals = line.split("\t") 
    if len(vals) == 7 : 
        domain, domain_specified, path, secure, expires, name, value = vals 
    if len(vals) == 6 : 
        domain, domain_specified, path, secure, name, value = vals 
        expires = None 
    

Infine spero davvero l'attuazione potrebbe essere aggiornato con i nuovi cambiamenti.

Problemi correlati