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 ответа:
Это не ошибка, а скорее разница в интерпретации. Согласно проекту роботы.спецификация txt (которая никогда не была одобрена, да и вряд ли будет):
Чтобы определить, разрешен ли доступ к URL-адресу, робот должен попытаться сопоставьте пути в разрешающих и запрещающих строках с URL-адресом, в порядок их появления в записи. Используется первое найденное совпадение. Если нет соответствие найдено, по умолчанию предполагается, что URL-адрес разрешено.
(раздел 3.2.2, строки разрешить и запретить)
Используя эту интерпретацию, то " / каталоги/p?"должно быть отклонено, потому что ранее существовала директива" Disallow: /catalogs".
В какой-то момент Google начал интерпретировать роботов.txt отличается от этой спецификации. Их метод, по-видимому, таков:Проблема заключается в том, что нет никакого формального согласия относительно интерпретации роботов.формат txt. Я видел краулеров, которые используют метод Google и другие, использующие проект стандарта 1996 года. Когда я работал с краулером, я получал настиграммы от веб-мастеров, когда я использовал интерпретацию Google, потому что я просматривал страницы, которые они считали, что не должны быть просмотрены, и я получал настиграммы от других, если я использовал другую интерпретацию, потому что вещи, которые они считали, должны быть проиндексированы, не были.Check for Allow. If it matches, crawl the page. Check for Disallow. If it matches, don't crawl. Otherwise, crawl.
После нескольких поисков в Google я не нашел ничего о проблемеrobotparser . Я закончил с чем-то другим, я нашел модуль под названием реппи что я сделал несколько тестов, и это кажется очень мощным. Вы можете установить его через pip;
Вот несколько примеров (на IPython) использования reppy, опять же, используя роботов Google .txtpip install reppy
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')