2013-03-11 31 views
5

Piszę robota i do tego implementuję parser robots.txt, używam standardowej biblioteki robotparser.Robotparser nie parsuje się poprawnie

Wydaje się, że robotparser jest nie analizowania poprawnie, jestem debugowania robota przy użyciu Google robots.txt.

(po przykłady z ipython)

In [1]: import robotparser 

In [2]: x = robotparser.RobotFileParser() 

In [3]: x.set_url("http://www.google.com/robots.txt") 

In [4]: x.read() 

In [5]: x.can_fetch("My_Crawler", "/catalogs") # This should return False, since it's on Disallow 
Out[5]: False 

In [6]: x.can_fetch("My_Crawler", "/catalogs/p?") # This should return True, since it's Allowed 
Out[6]: False 

In [7]: x.can_fetch("My_Crawler", "http://www.google.com/catalogs/p?") 
Out[7]: False 

To zabawne, bo czasami wydaje się, że „praca”, a czasem wydaje się nie uda, ja też próbowałem to samo z robots.txt z Facebook i Stackoverflow. Czy jest to błąd z modułu robotpaser? Czy robię coś złego tutaj? Jeśli tak to co?

Zastanawiałem się, czy this bug miał coś związanego

+0

Używam również Python 2.7.3 na maszynie Linux (Arch Linux) –

Odpowiedz

2

Po kilku wyszukiwania Google nie znalazłem nic o robotparser emisyjnej. Skończyło się na czymś innym, znalazłem moduł o nazwie reppy, który zrobiłem kilka testów i wydaje się bardzo silny. Możesz zainstalować go poprzez pip;

pip install reppy 

Oto kilka przykładów (na ipython) stosując reppy, ponownie, używając robots.txt

In [1]: import reppy 

In [2]: x = reppy.fetch("http://google.com/robots.txt") 

In [3]: x.atts 
Out[3]: 
{'agents': {'*': <reppy.agent at 0x1fd9610>}, 
'sitemaps': ['http://www.gstatic.com/culturalinstitute/sitemaps/www_google_com_culturalinstitute/sitemap-index.xml', 
    'http://www.google.com/hostednews/sitemap_index.xml', 
    'http://www.google.com/sitemaps_webmasters.xml', 
    'http://www.google.com/ventures/sitemap_ventures.xml', 
    'http://www.gstatic.com/dictionary/static/sitemaps/sitemap_index.xml', 
    'http://www.gstatic.com/earth/gallery/sitemaps/sitemap.xml', 
    'http://www.gstatic.com/s2/sitemaps/profiles-sitemap.xml', 
    'http://www.gstatic.com/trends/websites/sitemaps/sitemapindex.xml']} 

In [4]: x.allowed("/catalogs/about", "My_crawler") # Should return True, since it's allowed. 
Out[4]: True 

In [5]: x.allowed("/catalogs", "My_crawler") # Should return False, since it's not allowed. 
Out[5]: False 

In [7]: x.allowed("/catalogs/p?", "My_crawler") # Should return True, since it's allowed. 
Out[7]: True 

In [8]: x.refresh() # Refresh robots.txt, perhaps a magic change? 

In [9]: x.ttl 
Out[9]: 3721.3556718826294 

In [10]: # It also has a x.disallowed function. The contrary of x.allowed 
2

ciekawe pytanie Google. Miałem spojrzenie na źródła (i tylko Python 2.4 dostępne źródło, ale założę się, że nie zmieniła się) oraz kod normalizuje URL, który jest testowany przez wykonanie:

urllib.quote(urlparse.urlparse(urllib.unquote(url))[2]) 

który jest źródłem twoje problemy: „?”

>>> urllib.quote(urlparse.urlparse(urllib.unquote("/foo"))[2]) 
'/foo' 
>>> urllib.quote(urlparse.urlparse(urllib.unquote("/foo?"))[2]) 
'/foo' 

więc to albo błąd w bibliotece Pythona lub Google łamie specyfikacje robot.txt przez włączenie znak w regule (co jest trochę niezwykłe).

[na wypadek, gdyby nie było jasne, powiem to jeszcze raz w inny sposób. powyższy kod jest używany przez bibliotekę robotparser w ramach sprawdzania adresu URL. więc kiedy adres URL kończy się na "?" ta postać zostaje upuszczona. więc po sprawdzeniu, czy jest to /catalogs/p?, rzeczywisty wykonany test był dla /catalogs/p. stąd twój zaskakujący wynik.]

Proponuję filing a bug z pythonami (możesz zamieścić link tutaj w ramach wyjaśnień) [edytuj: dziękuję]. a następnie przy użyciu innej znalezionej biblioteki ...

+0

Dzięki! Masz rację, zrobiłem to samo sprawdzając z biblioteką, którą znalazłem i niestety robią to samo, chociaż działa lepiej niż robotaparser, wydają się takie same. Zgłosiłem błąd -> http://bugs.python.org/issue17403 –

1

Około tygodnia temu połączyliśmy commit z błędem, który powoduje ten problem. Popchnęliśmy wersję 0.2.2 do pip i master w repo, w tym test regresji dla dokładnie tego problemu.

Wersja 0.2 zawiera niewielką zmianę interfejsu - teraz musisz utworzyć obiekt RobotsCache, który zawiera dokładny interfejs, który pierwotnie miał reppy. Chodziło głównie o wyraźne buforowanie i umożliwianie różnych buforów w ramach tego samego procesu.Ale oto teraz działa znowu!

from reppy.cache import RobotsCache 
cache = RobotsCache() 
cache.allowed('http://www.google.com/catalogs', 'foo') 
cache.allowed('http://www.google.com/catalogs/p', 'foo') 
cache.allowed('http://www.google.com/catalogs/p?', 'foo') 
+1

Dzięki! To wspaniale! +10 dla Reppy, zrobił szybki problem, w niecałe 24 godziny został rozwiązany! Dzięki jeszcze raz! –

4

To nie jest błąd, ale raczej różnica w interpretacji. Według draft robots.txt specification (który nigdy nie został zatwierdzony, nie jest to prawdopodobne):

Aby ocenić, czy dostęp do adresu URL jest dozwolone, robot musi próbować dopasować ścieżki w Allow i Disallow linie przed URL w zamówieniu , w którym występują one w rekordzie. Używane jest pierwsze znalezione dopasowanie. Jeśli zostanie znalezione dopasowanie, domyślnym założeniem jest, że adres URL jest dozwolony.

(Sekcja 3.2.2, Allow i Disallow Lines)

Stosując tę ​​interpretację, a następnie "/ katalogi/s?" należy odrzucić, ponieważ wcześniej obowiązywała dyrektywa "Disallow:/katalogi".

W pewnym momencie Google zaczęło interpretować plik robots.txt inaczej niż ta specyfikacja. Ich metoda wydaje się być:

Check for Allow. If it matches, crawl the page. 
Check for Disallow. If it matches, don't crawl. 
Otherwise, crawl. 

Problemem jest to, że nie ma formalnego porozumienia w sprawie interpretacji robots.txt. Widziałem roboty korzystające z metody Google i inne, które korzystają z wersji standardowej z 1996 roku. Gdy pracowałem z robotem indeksującym, otrzymałem złośliwe gramy od webmasterów, gdy korzystałem z interpretacji Google, ponieważ przeszukiwałem strony, które według nich nie powinny być indeksowane, i dostałem nastygramy od innych, jeśli użyłem drugiej interpretacji, ponieważ rzeczy, które według nich powinny być indeksowane, nie były.