Robotparser, кажется, не разбирает правильно


Я пишу гусеничный движитель и для этого внедряю роботов.txt parser, я использую стандартный lib роботпарсер.

Похоже, чтоrobotparser неразбирает правильно, я отлаживаю свой искатель с помощью роботов Google .txt .

(следующие примеры взяты из 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

Это забавно, потому что иногда кажется, что это "работает", а иногда кажется, что это не работает, я также пытался сделать то же самое с роботами.txt от Facebook и Stackoverflow. Это ошибка из модуля robotpaser? Или я делаю что-то не так? Если да, то что?

Мне было интересно, имеет ли этот баг что-нибудь общее

4 6

4 ответа:

Это не ошибка, а скорее разница в интерпретации. Согласно проекту роботы.спецификация txt (которая никогда не была одобрена, да и вряд ли будет):

Чтобы определить, разрешен ли доступ к URL-адресу, робот должен попытаться сопоставьте пути в разрешающих и запрещающих строках с URL-адресом, в порядок их появления в записи. Используется первое найденное совпадение. Если нет соответствие найдено, по умолчанию предполагается, что URL-адрес разрешено.

(раздел 3.2.2, строки разрешить и запретить)

Используя эту интерпретацию, то " / каталоги/p?"должно быть отклонено, потому что ранее существовала директива" Disallow: /catalogs".

В какой-то момент Google начал интерпретировать роботов.txt отличается от этой спецификации. Их метод, по-видимому, таков:
Check for Allow. If it matches, crawl the page.
Check for Disallow. If it matches, don't crawl.
Otherwise, crawl.
Проблема заключается в том, что нет никакого формального согласия относительно интерпретации роботов.формат txt. Я видел краулеров, которые используют метод Google и другие, использующие проект стандарта 1996 года. Когда я работал с краулером, я получал настиграммы от веб-мастеров, когда я использовал интерпретацию Google, потому что я просматривал страницы, которые они считали, что не должны быть просмотрены, и я получал настиграммы от других, если я использовал другую интерпретацию, потому что вещи, которые они считали, должны быть проиндексированы, не были.

После нескольких поисков в Google я не нашел ничего о проблемеrobotparser . Я закончил с чем-то другим, я нашел модуль под названием реппи что я сделал несколько тестов, и это кажется очень мощным. Вы можете установить его через pip;

pip install reppy
Вот несколько примеров (на IPython) использования reppy, опять же, используя роботов Google .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

Интересный вопрос. я посмотрел на исходный код (у меня есть только исходный код python 2.4, но я уверен, что он не изменился), и код нормализует url, который тестируется путем выполнения:

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

Что является источником ваших проблем:

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

Так что это либо ошибка в библиотеке python, либо google ломает робота.технические характеристики тхт, включив "?"характер в правиле (что немного необычно).

[на всякий случай, если это не ясно, я повторю это снова по-другому. приведенный выше код используется библиотекой robotparser как часть проверки url-адреса. Итак, когда url-адрес заканчивается на"?- этот персонаж отброшен. поэтому, когда вы проверяли для /catalogs/p?, фактический тест выполнялся для /catalogs/p. отсюда и ваш удивительный результат.]

Я бы предложил подать ошибку с людьми python (вы можете разместить ссылку здесь как часть объяснения) [edit: thanks]. а затем использовать другую библиотеку, которую вы нашли...

Около недели назад мы слили коммит с ошибкой в нем, которая вызывает эту проблему. Мы просто выдвинули версию 0.2.2 на pip и master в репо, включая регрессионный тест именно для этой проблемы.

Версия 0.2 содержит небольшое изменение интерфейса - теперь вы должны создать объект RobotsCache, который содержит точный интерфейс, который первоначально имел reppy. Это было сделано главным образом для того, чтобы сделать кэширование явным и сделать возможным иметь различные кэши в рамках одного и того же процесса. Но вот, это сейчас опять работает!

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')