首页 > Python > Python 3 标准库实例教程 > 互联网数据处理

13.4. urllib.robotparser — 互联网爬虫访问控制

目标:解析用于控制网络怕爬虫的 robots.txt 文件

robotparser 实现了一个用于分析 robots.txt 文件格式的解析器, 它含有一个检查给定用户代理是否可以访问给定资源的函数。它的目的是给那些品行端正的爬虫用的,或用来指导需要节流,否则就会被限制访问的其他抓取器。

robots.txt

robots.txt 文件是一个简单的基于文本的访问控制系统,用于控制那些自动访问网络资源的程序(如「爬虫」,「抓取器」,等等)。文件由特定的用户代理程序标识的记录以及代理不允许访问的 URLs (或 URL 前缀) 的一个列表组成。

以下是  https://pymotw.com/robots.txt 文件

robots.txt


Sitemap: https://pymotw.com/sitemap.xml
User-agent: *
Disallow: /admin/
Disallow: /downloads/
Disallow: /media/
Disallow: /static/
Disallow: /codehosting/

它阻止访问网站的某些部分,因为如果一个搜索引擎对该部分进行索引将需要大量计算且容易导致服务器过载。更多完整的 robots.txt 例子,请参考 The Web Robots Page

测试访问许可

使用前面呈现过的数据,一个简单的抓取器可以用 RobotFileParser.can_fetch() 测试它是否被允许下载一个页面。

urllib_robotparser_simple.py

from urllib import parse
from urllib import robotparser

AGENT_NAME = 'PyMOTW'
URL_BASE = 'https://pymotw.com/'
parser = robotparser.RobotFileParser()
parser.set_url(parse.urljoin(URL_BASE, 'robots.txt'))
parser.read()

PATHS = [
    '/',
    '/PyMOTW/',
    '/admin/',
    '/downloads/PyMOTW-1.92.tar.gz',
]

for path in PATHS:
    print('{!r:>6} : {}'.format(
        parser.can_fetch(AGENT_NAME, path), path))
    url = parse.urljoin(URL_BASE, path)
    print('{!r:>6} : {}'.format(
        parser.can_fetch(AGENT_NAME, url), url))
    print()

can_fetch() 函数的 URL 参数可以是相对网站根目录的相对路径或是完整的 URL 。

$ python3 urllib_robotparser_simple.py

  True : /
  True : https://pymotw.com/

  True : /PyMOTW/
  True : https://pymotw.com/PyMOTW/

 False : /admin/
 False : https://pymotw.com/admin/

 False : /downloads/PyMOTW-1.92.tar.gz
 False : https://pymotw.com/downloads/PyMOTW-1.92.tar.gz

长寿爬虫

那些需要很长时间来处理下载好的资源或者为了节流在两次下载之间会有停顿的应用,应该基于已下载内容的时长来周期检查新的 robots.txt 文件。虽然不能自动管理时长,但要跟踪它,却有易用的方法可以让这件事变简单。

urllib_robotparser_longlived.py

from urllib import robotparser
import time

AGENT_NAME = 'PyMOTW'
parser = robotparser.RobotFileParser()
# Using the local copy
parser.set_url('file:robots.txt')
parser.read()
parser.modified()

PATHS = [
    '/',
    '/PyMOTW/',
    '/admin/',
    '/downloads/PyMOTW-1.92.tar.gz',
]

for path in PATHS:
    age = int(time.time() - parser.mtime())
    print('age:', age, end=' ')
    if age > 1:
        print('rereading robots.txt')
        parser.read()
        parser.modified()
    else:
        print()
    print('{!r:>6} : {}'.format(
        parser.can_fetch(AGENT_NAME, path), path))
    # Simulate a delay in processing
    time.sleep(1)
    print()

在这个极端的例子中,每当已获取的 robots.txt 文件存在超过一秒就会重新下载一个新的。

$ python3 urllib_robotparser_longlived.py

age: 0
  True : /

age: 1
  True : /PyMOTW/

age: 2 rereading robots.txt
 False : /admin/

age: 1
 False : /downloads/PyMOTW-1.92.tar.gz

针对长寿应用的一个更好的版本也许应该在下载整个文件之前询问一下文件最后修改的时间。但另一方面, robots.txt 文件通常都很小,所以即使再次获取整个文件也不会多太多代价。

参考