在HTTP中对远程文件进行Python寻址

11 投票
4 回答
8625 浏览
提问于 2025-04-15 17:26

我想知道怎么在一个远程(HTTP)文件中找到特定的位置,这样我就可以只下载那部分内容。

假设远程文件中的字节是:1234567890

我想从第4个字节开始,下载3个字节,这样我就会得到:456

另外,我还想知道怎么检查一个远程文件是否存在?我试过用 os.path.isfile(),但是当我传入一个远程文件的链接时,它返回的是 False。

4 个回答

4

据我所知,使用fseek()或类似的函数是无法做到这一点的。你需要使用HTTP的Range头来实现这个功能。不过,这个头部可能会被服务器支持,也可能不会,所以具体情况可能会有所不同。

import urllib2

myHeaders = {'Range':'bytes=0-9'}

req = urllib2.Request('http://www.promotionalpromos.com/mirrors/gnu/gnu/bash/bash-1.14.3-1.14.4.diff.gz',headers=myHeaders)

partialFile = urllib2.urlopen(req)

s2 = (partialFile.read())

补充一下,这里假设你说的远程文件是指存储在HTTP服务器上的文件...

如果你想要的文件是在FTP服务器上,FTP只允许你指定一个起始偏移量,而不是一个范围。如果你想要这样做,下面的代码应该可以实现(不过没有测试过!)

import ftplib
fileToRetrieve = 'somefile.zip'
fromByte = 15
ftp = ftplib.FTP('ftp.someplace.net')
outFile = open('partialFile', 'wb')
ftp.retrbinary('RETR '+ fileToRetrieve, outFile.write, rest=str(fromByte))
outFile.close()
6

我非常推荐使用requests这个库。它绝对是我用过的最好的HTTP库。特别是为了完成你所描述的事情,你可以这样做:

import requests

url = "http://www.sffaudio.com/podcasts/ShellGameByPhilipK.Dick.pdf"

# Retrieve bytes between offsets 3 and 5 (inclusive).
r = requests.get(url, headers={"range": "bytes=3-5"})

# If a 4XX client error or a 5XX server error is encountered, we raise it.
r.raise_for_status()
16

如果你是通过HTTP下载远程文件,你需要设置一个叫做Range的头部信息。

可以参考这个例子,看看怎么做。大概是这样的:

myUrlclass.addheader("Range","bytes=%s-" % (existSize))

编辑: 我刚找到一个更好的实现方式。这个类使用起来非常简单,文档里有说明。

class HTTPRangeHandler(urllib2.BaseHandler):
"""Handler that enables HTTP Range headers.

This was extremely simple. The Range header is a HTTP feature to
begin with so all this class does is tell urllib2 that the 
"206 Partial Content" reponse from the HTTP server is what we 
expected.

Example:
    import urllib2
    import byterange

    range_handler = range.HTTPRangeHandler()
    opener = urllib2.build_opener(range_handler)

    # install it
    urllib2.install_opener(opener)

    # create Request and set Range header
    req = urllib2.Request('http://www.python.org/')
    req.header['Range'] = 'bytes=30-50'
    f = urllib2.urlopen(req)
"""

def http_error_206(self, req, fp, code, msg, hdrs):
    # 206 Partial Content Response
    r = urllib.addinfourl(fp, hdrs, req.get_full_url())
    r.code = code
    r.msg = msg
    return r

def http_error_416(self, req, fp, code, msg, hdrs):
    # HTTP's Range Not Satisfiable error
    raise RangeError('Requested Range Not Satisfiable')

更新: 这个“更好的实现”现在已经移到github: excid3/urlgrabber,具体在byterange.py文件里。

撰写回答