2012-07-17 12 views
7

Piszę parser Google Scholar i na podstawie this answer, ustawiam ciasteczka przed przechwyceniem kodu HTML. Jest to zawartość mojego cookies.txt pliku:Dlaczego Python twierdzi, że plik cookie Netscape jest nieprawidłowy?

# 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 

i jest to kod używam chwycić 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) 

Pełne traceback jest:

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 Rozejrzałem się za dokumentacją w formacie pliku cookie Netscape, ale nie mogę znaleźć niczego, co wskazywałoby na problem. Czy istnieją nowe linie, które należy uwzględnić? Zmieniłem końcówki linii na styl Unix, na wszelki wypadek, ale to nie rozwiązało problemu. Najbliższą specyfikacją, jaką mogę znaleźć, jest this, co nie oznacza niczego, czego mi brakuje. Pola na każdej z czterech ostatnich linii są oddzielone tabulatorami, a nie spacjami, a wszystko inne wygląda dla mnie poprawnie.

+0

[Netscape specyfikacja cookies] (http://curl.haxx.se/rfc/cookie_spec.html), który kiedyś gościł na netscape.com przed kimś (AOL?) Zniszczony historię. – n611x007

+0

zaktualizowany Spec jako [typu RFC2965] (http://tools.ietf.org/html/rfc2965.html) z * Set-Cookie2 * – n611x007

+0

Dla wszystkich zainteresowanych, faktycznie można zrobić „cookies.save (cookie_file, ignore_discard = true , ignore_expires = True) ", aby utworzyć prawidłowy plik cookie jako instancję do porównania z nieprawidłowymi cookies.txt. Linia po linii lub bye by bajt porównać i usunąć linię jeden po drugim, można znaleźć przyczynę w końcu. –

Odpowiedz

10

Nic nie widzę w twoim przykładowym kodzie lub kopii pliku cookie.txt, który jest oczywiście nieprawidłowy.

Sprawdziłem kod źródłowy dla MozillaCookieJar._really_load method, która zgłasza wyjątek, który widzisz.

Pierwszą rzeczą, ta metoda nie jest odczytać pierwszy wiersz pliku określonym (używając f.readline()) i używać re.search szukać wzorcu wyrażenia regularnego "#(Netscape)? HTTP Cookie File". To się nie udaje dla twojego pliku.

To na pewno wygląda podobnie jak twój cookies.txt pasuje do tego formatu, więc błąd, który widzisz, jest dość zaskakujący.

Wcześniejszy plik zostanie otwarty za pomocą prostego open(filename) call, więc zostanie otwarty w trybie tekstowym z obsługą uniwersalnego zakończenia linii, co oznacza, że ​​nie ma znaczenia, że ​​uruchamiasz to w systemie Windows. Kod zobaczy ciągi zakończone znakiem nowej linii, bez względu na to, jaka konwencja linii nowej została użyta w samym pliku.

Co zrobiłbym w tym przypadku to potrójne sprawdzenie, że pierwszy wiersz twojego pliku jest naprawdę poprawny. Musi zawierać "# HTTP Cookie File" lub "# Netscape HTTP Cookie File" (tylko spacje, brak kart, między słowami, dopasowywanie wielkich liter). Przetestuj to z wiersza Pythona:

>>> 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 echem reprezentację linii z powrotem do mnie, gdy wpisałem line w wierszu, w tym charakteru \n nowej linii. Wszelkie niespodzianki, takie jak znaki tabulacji lub przestrzenie o zerowej szerokości Unicode, pojawią się tam jako kody ucieczki. Sprawdziłem również, czy wyrażenie regularne używane przez kod cookiejar jest zgodne.

Można również użyć pdb python debugger do sprawdzenia co moduł http.cookiejar naprawdę robi:

>>> 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: 

W powyższym próbka pdb sesji użyłem kombinację step i next poleceń w celu zweryfikowania, że ​​test wyrażenie regularne (self.magic_re.search(magic)) faktycznie przeszedł.

+0

Doskonała odpowiedź! (i świetny przykład debugowania pythona). Nie wiem, czy coś innego zmieniło się w moim systemie, ale kod działa w tej chwili bez żadnych zmian w "cookies.txt" Pierwsza linia pliku była identyczna z twoją, włączając spacje, tabulatory itp., Więc nie jestem pewien, jaki problem wywołał problem. –

+0

@RicardoAltamirano to tylko przypuszczenie: zmiana kodowania tekstu, np. wiodące BOM, takie jak nieoficjalne utf-8 '\ xef \ xbb \ xbf' może spowodować taki efekt i może nie być oczywiste, ponieważ zmieniła się tylko zawartość binarna, ale jako tekst może wyglądać tak samo. Ten sam pomysł mógłby się zmienić w kodzie, jeśli wcześniej używałeś 'open' i późniejszego' codecs.open'. – n611x007

+0

@naxa: sesja 'open()' i 'f.readline()', którą pokazuję w mojej odpowiedzi (w Pythonie 2), z łatwością pokazałaby każdy taki kodek. IIRC BOM UTF-8 nadal będzie częścią wartości Unicode zwróconej z obiektu 'codecs.open()' lub 'io.open()', a literałowy napis "un'" będzie martwym gratisiem w każdym przypadku. –

2

Jako mojego scenariusza, dwie modyfikacje są potrzebne do MozillaCookieJar mocy (/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/)

  1. Magia nagłówka

    można usunąć lub dodać logikę wyboru, że magia nagłówek które wolę

    „# Netscape HTTP Cookie File

  2. Nowy format pliku wydaje pozwalają pominąć wygasa

    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 
    

Wreszcie mam nadzieję realizacja mogłaby być aktualizowane do nowych zmian.

Powiązane problemy