Ответ 1
Я не уверен, как работает реализация С#, но поскольку интернет-потоки, как правило, не доступны для поиска, я предполагаю, что он загружает все данные в локальный файл или объект в памяти и ищет внутри него. Эквивалент Python этого будет заключаться в том, чтобы предлагать Abafei и записывать данные в файл или StringIO и искать оттуда.
Однако, если, как указывает ваш комментарий к ответам Abafei, вы хотите получить только определенную часть файла (вместо того, чтобы искать назад и вперед через возвращаемые данные), есть еще одна возможность. urllib2
может использоваться для извлечения определенного раздела (или "диапазона" на языке HTTP) веб-страницы при условии, что сервер поддерживает это поведение.
Заголовок range
Когда вы отправляете запрос на сервер, параметры запроса указываются в разных заголовках. Одним из них является заголовок range
, определенный в разделе раздела 14.35 RFC2616 (спецификация, определяющая HTTP/1.1). Этот заголовок позволяет делать такие вещи, как получение всех данных, начиная с 10 000-го байта, или данных между байтами 1000 и 1500.
Поддержка сервера
Нет необходимости поддерживать сервер для поддержки поиска диапазона. Некоторые серверы вернут заголовок Accept-Ranges
(раздел 14.5 RFC2616) вместе с ответом на отчет, если они поддерживают диапазоны или нет. Это можно проверить с помощью запроса HEAD. Однако нет особой необходимости в этом; если сервер не поддерживает диапазоны, он вернет всю страницу, и мы сможем затем извлечь нужную часть данных в Python, как и раньше.
Проверка возврата диапазона
Если сервер возвращает диапазон, он должен отправить заголовок Content-Range
(раздел 14.16 RFC2616) вместе с ответом. Если это присутствует в заголовках ответа, мы знаем, что диапазон был возвращен; если его нет, вся страница была возвращена.
Реализация с помощью urllib2
urllib2
позволяет нам добавлять заголовки к запросу, что позволяет нам запрашивать сервер для диапазона, а не всей страницы. Следующий script принимает URL-адрес, начальную позицию и (необязательно) длину в командной строке и пытается получить заданный раздел страницы.
import sys
import urllib2
# Check command line arguments.
if len(sys.argv) < 3:
sys.stderr.write("Usage: %s url start [length]\n" % sys.argv[0])
sys.exit(1)
# Create a request for the given URL.
request = urllib2.Request(sys.argv[1])
# Add the header to specify the range to download.
if len(sys.argv) > 3:
start, length = map(int, sys.argv[2:])
request.add_header("range", "bytes=%d-%d" % (start, start + length - 1))
else:
request.add_header("range", "bytes=%s-" % sys.argv[2])
# Try to get the response. This will raise a urllib2.URLError if there is a
# problem (e.g., invalid URL).
response = urllib2.urlopen(request)
# If a content-range header is present, partial retrieval worked.
if "content-range" in response.headers:
print "Partial retrieval successful."
# The header contains the string 'bytes', followed by a space, then the
# range in the format 'start-end', followed by a slash and then the total
# size of the page (or an asterix if the total size is unknown). Lets get
# the range and total size from this.
range, total = response.headers['content-range'].split(' ')[-1].split('/')
# Print a message giving the range information.
if total == '*':
print "Bytes %s of an unknown total were retrieved." % range
else:
print "Bytes %s of a total of %s were retrieved." % (range, total)
# No header, so partial retrieval was unsuccessful.
else:
print "Unable to use partial retrieval."
# And for good measure, lets check how much data we downloaded.
data = response.read()
print "Retrieved data size: %d bytes" % len(data)
Используя это, я могу получить последние 2000 байт домашней страницы Python:
[email protected]:~$ python retrieverange.py http://www.python.org/ 17387
Partial retrieval successful.
Bytes 17387-19386 of a total of 19387 were retrieved.
Retrieved data size: 2000 bytes
Или 400 байт с середины главной страницы:
[email protected]:~$ python retrieverange.py http://www.python.org/ 6000 400
Partial retrieval successful.
Bytes 6000-6399 of a total of 19387 were retrieved.
Retrieved data size: 400 bytes
Однако главная страница Google не поддерживает диапазоны:
[email protected]:~$ python retrieverange.py http://www.google.com/ 1000 500
Unable to use partial retrieval.
Retrieved data size: 9621 bytes
В этом случае необходимо было бы извлечь интересующие данные в Python до дальнейшей обработки.