Использование http get метода и программирования сокетов для загрузки txt файла в python - PullRequest
0 голосов
/ 25 октября 2019

Я пытаюсь загрузить текстовый файл, используя python и сокеты, но возникает ошибка, когда я декодирую содержимое, которое я получаю.

Я использую python3 и запускаю test.py на окнах, пытаясь получитьсодержимое http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt

 python .\test.py linux.vbird.org 80 /linux_basic/0330regularex/regular_express.txt
# this file is named test.py
import socket
import sys

host = sys.argv[1]
port = sys.argv[2]
filename = sys.argv[3]
# creating a socket, using ipv4
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connecting
s.connect((host, int(port)))
print("Connecting successful!\n")
str = "GET %s HTTP/1.0\r\n\r\n" % filename
s.sendall(str.encode('utf-8'))
while 1:
    try:
        buf = s.recv(2048)
    except socket.error as e:
        print("Error receiving data: %s" % e)
        sys.exit(1)
    if not len(buf):
        break
    sys.stdout.write(buf.decode('utf-8'))

Я ожидал получить содержимое данного URL, а именно содержимое txt-файла, однако сообщение об ошибке выглядит следующим образом:


Соединение успешно!

Traceback (последний вызов был последним): файл ". \ Test.py", строка 22, в sys.stdout.write (buf.decode ('utf-8'))UnicodeDecodeError: кодек «utf-8» не может декодировать байт 0xb3 в позиции 275: недопустимый начальный байт


Ответы [ 2 ]

1 голос
/ 25 октября 2019

Заголовок HTTP - ASCII и не более iso-8859-1 (однобайтовая кодировка "ü" и т. Д.). Это не utf-8 (многобайтовая кодировка "ü" и т. Д.). Кодировка тела HTTP может быть любой, то есть тело должно обрабатываться как байты, если кодировка неизвестна.

Кодировка может быть задана в атрибуте "charset" в заголовке ответа Content-Type в случае текста или HTML. Это не требуется, хотя. В случае HTML это также может быть дано внутри метатега. Если он не указан, получатель может использовать значения по умолчанию (которые могут не соответствовать фактической кодировке) или использовать эвристику, чтобы угадать кодировку .

0 голосов
/ 25 октября 2019

Первоначально это был ответ на ваш вопрос в комментарии о сообщении "DO NOT USE vbird.org" - но, наконец, это решило и другую проблему.


linux.vbird.org и vbird.org имеют одинаковый IP-адрес. Они находятся на одном сервере.

Сокет преобразует linux.vbird.org в IP и использует IP для подключения к серверу - поэтому сервер не знает, что вы хотите получить файл с linux.vbird.org. Он думает, что вы хотите от vbird.org, который является основным доменом. linux.vbird.org является единственным поддоменом в домене vbird.org.

Вам потребуется использовать заголовок host: linux.vbird.org в запросе, чтобы сообщить серверу, с какого субдомена вы пытаетесь получить файл.

GET /linux_basic/0330regularex/regular_express.txt HTTP/1.0
Host: linux.vbird.org

С этим заголовком он отправляет ваш файл.

Я проверил этот заголовок с вашим кодом и случайно решил проблему с кодировкой, поскольку ваш файл находится в UTF-8 и сервер отправил его какUTF-8 и нет проблем с buf.decode('utf-8')


import socket
import sys

host = 'linux.vbird.org' 
port = '80'
filename = '/linux_basic/0330regularex/regular_express.txt'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, int(port)))
print("Connecting successful!\n")

str = "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (filename,host)
print(str)

s.sendall(str.encode('utf-8'))
while True:
    try:
        buf = s.recv(2048)
    except socket.error as e:
        print("Error receiving data: %s" % e)
        sys.exit(1)
    if not len(buf):
        break

    #print(buf)
    sys.stdout.write(buf.decode('utf-8'))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...