Skip to content

Commit cdcf228

Browse files
ephphathablurb-it[bot]orsenthilserhiy-storchaka
authored
gh-60055: Allow passing a Request instance for RobotParser URLs (#103753)
* Allow passing a Request instance for the url parameter * 📜🤖 Added by blurb_it. * gh-60055: rebase onto main and document Request support * Fix the lint warnings and CI Errors. * Addressing RobotFileParser review comments. * Update Doc/library/urllib.robotparser.rst Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> * Address additional Review Comments. * Changed versionchanged to next. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Senthil Kumaran <senthil@python.org> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent d0921ef commit cdcf228

4 files changed

Lines changed: 61 additions & 3 deletions

File tree

Doc/library/urllib.robotparser.rst

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,18 @@ structure of :file:`robots.txt` files, see :rfc:`9309`.
2424
.. class:: RobotFileParser(url='')
2525

2626
This class provides methods to read, parse and answer questions about the
27-
:file:`robots.txt` file at *url*.
27+
:file:`robots.txt` file at *url* or a :class:`urllib.request.Request` object.
28+
29+
.. versionchanged:: next
30+
*url* parameter can be a :class:`urllib.request.Request` object.
2831

2932
.. method:: set_url(url)
3033

31-
Sets the URL referring to a :file:`robots.txt` file.
34+
Sets the URL referring to a :file:`robots.txt` file or a
35+
:class:`urllib.request.Request` object.
36+
37+
.. versionchanged:: next
38+
*url* parameter can be a :class:`urllib.request.Request` object.
3239

3340
.. method:: read()
3441

@@ -102,3 +109,17 @@ class::
102109
True
103110
>>> rp.can_fetch("*", "http://www.pythontest.net/no-robots-here/")
104111
False
112+
113+
114+
The following example demonstrates use of a :class:`urllib.request.Request`
115+
object with additional user-agent headers populated::
116+
117+
>>> import urllib.robotparser
118+
>>> import urllib.request
119+
>>> rp = urllib.robotparser.RobotFileParser()
120+
>>> rp.set_url(urllib.request.Request("http://www.pythontest.net/robots.txt", headers={"User-Agent": "IsraBot"}))
121+
>>> rp.read()
122+
>>> rp.can_fetch("*", "http://www.pythontest.net/")
123+
True
124+
>>> rp.can_fetch("*", "http://www.pythontest.net/no-robots-here/")
125+
False

Lib/test/test_robotparser.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,37 @@ def testServiceUnavailable(self):
773773
self.assertFalse(parser.can_fetch("*", url + '/path/file.html'))
774774

775775

776+
class UserAgentSiteTestCase(BaseLocalNetworkTestCase, unittest.TestCase):
777+
778+
class RobotHandler(BaseHTTPRequestHandler):
779+
def do_GET(self):
780+
if self.headers.get('User-Agent').startswith('Python-urllib'):
781+
self.send_error(403, "Forbidden access")
782+
else:
783+
self.send_response(200)
784+
self.end_headers()
785+
self.wfile.write(b"User-agent: *\nDisallow:")
786+
787+
def log_message(self, format, *args):
788+
pass
789+
790+
def testUserAgentFilteringSite(self):
791+
addr = self.server.server_address
792+
url = f'http://{socket_helper.HOST}:{addr[1]}'
793+
robots_url = url + "/robots.txt"
794+
file_url = url + "/document"
795+
parser = urllib.robotparser.RobotFileParser()
796+
parser.set_url(robots_url)
797+
parser.read()
798+
self.assertTrue(parser.disallow_all)
799+
self.assertFalse(parser.can_fetch("*", file_url))
800+
parser = urllib.robotparser.RobotFileParser()
801+
parser.set_url(urllib.request.Request(robots_url, headers={'User-Agent': 'cybermapper'}))
802+
parser.read()
803+
self.assertFalse(parser.disallow_all)
804+
self.assertTrue(parser.can_fetch("*", file_url))
805+
806+
776807
@support.requires_working_socket()
777808
class NetworkTestCase(unittest.TestCase):
778809

Lib/urllib/robotparser.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,13 @@ def modified(self):
5555
self.last_checked = time.time()
5656

5757
def set_url(self, url):
58-
"""Sets the URL referring to a robots.txt file."""
58+
"""Sets the URL referring to a robots.txt file.
59+
can be a string or a Request object.
60+
"""
5961
self.url = url
62+
63+
if isinstance(url, urllib.request.Request):
64+
url = url.full_url
6065
self.host, self.path = urllib.parse.urlsplit(url)[1:3]
6166

6267
def read(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Let ``urllib.robotparser.RobotFileParser`` accept a ``urllib.request.Request`` object as well as a url string when setting a robots.txt url.

0 commit comments

Comments
 (0)