Разбор ответа http в формате байтов - PullRequest
0 голосов
/ 07 марта 2020

requests.get() получает response, который имеет тип байтов. Это выглядит следующим образом:

b'{"Close":8506.25,"DownTicks":164,"DownVolume":207,"High":8508.25,"Low":8495.00,"Open":8496.75,"Status":13,"TimeStamp":"\\/Date(1583530800000)\\/","TotalTicks":371,"TotalVolume":469,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":207,"UpVolume":262,"OpenInterest":0}\r\n{"Close":8503.00,"DownTicks":152,"DownVolume":203,"High":8509.50,"Low":8502.00,"Open":8506.00,"Status":13,"TimeStamp":"\\/Date(1583531100000)\\/","TotalTicks":282,"TotalVolume":345,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":130,"UpVolume":142,"OpenInterest":0}\r\n{"Close":8494.00,"DownTicks":160,"DownVolume":206,"High":8505.75,"Low":8492.75,"Open":8503.25,"Status":13,"TimeStamp":"\\/Date(1583531400000)\\/","TotalTicks":275,"TotalVolume":346,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":115,"UpVolume":140,"OpenInterest":0}\r\n{"Close":8499.00,"DownTicks":136,"DownVolume":192,"High":8500.25,"Low":8492.25,"Open":8493.75,"Status":13,"TimeStamp":"\\/Date(1583531700000)\\/","TotalTicks":299,"TotalVolume":402,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":163,"UpVolume":210,"OpenInterest":0}\r\n{"Close":8501.75,"DownTicks":176,"DownVolume":314,"High":8508.25,"Low":8495.75,"Open":8498.50,"Status":536870941,"TimeStamp":"\\/Date(1583532000000)\\/","TotalTicks":340,"TotalVolume":510,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":164,"UpVolume":196,"OpenInterest":0}\r\nEND'

Обратите внимание, что хотя фактическая строка намного длиннее, она всегда представляет собой длинную строку из более коротких строк, разделенных '\r\n', игнорируя последнее слово «END». Вы можете видеть, насколько схожи эти короткие строки:

for i in response.text.split('\r\n')[:-1]: print(i, '\n\n')

{"Close":8506.25,"DownTicks":164,"DownVolume":207,"High":8508.25,"Low":8495.00,"Open":8496.75,"Status":13,"TimeStamp":"\/Date(1583530800000)\/","TotalTicks":371,"TotalVolume":469,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":207,"UpVolume":262,"OpenInterest":0} 


{"Close":8503.00,"DownTicks":152,"DownVolume":203,"High":8509.50,"Low":8502.00,"Open":8506.00,"Status":13,"TimeStamp":"\/Date(1583531100000)\/","TotalTicks":282,"TotalVolume":345,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":130,"UpVolume":142,"OpenInterest":0} 


{"Close":8494.00,"DownTicks":160,"DownVolume":206,"High":8505.75,"Low":8492.75,"Open":8503.25,"Status":13,"TimeStamp":"\/Date(1583531400000)\/","TotalTicks":275,"TotalVolume":346,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":115,"UpVolume":140,"OpenInterest":0} 


{"Close":8499.00,"DownTicks":136,"DownVolume":192,"High":8500.25,"Low":8492.25,"Open":8493.75,"Status":13,"TimeStamp":"\/Date(1583531700000)\/","TotalTicks":299,"TotalVolume":402,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":163,"UpVolume":210,"OpenInterest":0} 


{"Close":8501.75,"DownTicks":176,"DownVolume":314,"High":8508.25,"Low":8495.75,"Open":8498.50,"Status":536870941,"TimeStamp":"\/Date(1583532000000)\/","TotalTicks":340,"TotalVolume":510,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":164,"UpVolume":196,"OpenInterest":0} 

Цель парсинг нескольких полей и сохранение их в фрейме данных с полем " Временная метка »в качестве индекса датафрейма.

Что я сделал:

response_text = response.text

import ast

df = pd.DataFrame(columns = [ 'o', 'h', 'l', 'c', 'v'])

for i in response_text.split('\r\n')[:-1]:
    i_dict = ast.literal_eval(i)
    epoch_in_milliseconds = int(i_dict['TimeStamp'].split('(')[1].split(')')[0])

    time_stamp = datetime.datetime.fromtimestamp(float(epoch_in_milliseconds)/1000.)
    o = i_dict['Open']
    h = i_dict['High']
    l = i_dict['Low']
    c = i_dict['Close']
    v = i_dict['TotalVolume']
    temp_df = pd.DataFrame({'o':o, 'h':h, 'l':l, 'c':c, 'v':v}, index = [time_stamp])

    df = df.append(temp_df)

, что дает мне:

In [546]df
Out[546]: 
                             o          h          l          c    v
2020-03-06 16:40:00 8496.75000 8508.25000 8495.00000 8506.25000  469
2020-03-06 16:45:00 8506.00000 8509.50000 8502.00000 8503.00000  345
2020-03-06 16:50:00 8503.25000 8505.75000 8492.75000 8494.00000  346
2020-03-06 16:55:00 8493.75000 8500.25000 8492.25000 8499.00000  402
2020-03-06 17:00:00 8498.50000 8508.25000 8495.75000 8501.75000  510

, что именно то, что мне нужно.

Issue этот метод мне кажется неуклюжим, как пэчворк, и склонен к поломке из-за возможных небольших различий в тексте ответа.

Есть ли более надежный и быстрый способ извлечения этой информации из исходных байтов? (Когда ответ сервера в формате JSON, у меня нет этой головной боли)

Ответы [ 2 ]

0 голосов
/ 08 марта 2020

Это почти JSON формат. Точнее, это серия строк, каждая из которых содержит отформатированный JSON объект. (За исключением последнего.) Таким образом, это говорит о том, что оптимальное решение каким-то образом использует модуль json.

json.load не обрабатывает файлы, состоящие из серии строк, и не делает это напрямую обрабатывать отдельные строки (гораздо меньше bytes). Тем не менее, вы не ограничены json.load. Вы можете создать JSONDecoder объект , который включает методы для анализа строк (но не из bytes), и вы можете использовать метод decode объекта bytes для создания строка из ввода. (Для этого нужно знать кодировку, но я сильно подозреваю, что в этом случае все символы являются ascii, поэтому будет работать либо 'ascii', либо кодировка UTF-8 по умолчанию.)

Если только вы не введете данные в гигабайтах, вы можете просто использовать стратегию в своем вопросе: разбить ввод на строки, отбросить строку END и передать остальные в JSONDecoder:

import json
decoder = JSONDecoder()
# Using splitlines seemed more robust than counting on a specific line-end
for line in response_text.decode().splitlines()
    # Alternative: use a try/catch around the call to decoder.decode
    if line == 'END': break
    line_dict = decoder.decode(line)
    # Handle the Timestamp member and create the dataframe item
0 голосов
/ 08 марта 2020

Я считаю, что это несколько чище:

ts = """
b'{"Close":8506.25,"DownTicks":164,"DownVolume":207,"High":8508.25,"Low":8495.00,"Open":8496.75,"Status":13,"TimeStamp":"\\/Date(1583530800000)\\/","TotalTicks":371,"TotalVolume":469,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":207,"UpVolume":262,"OpenInterest":0}\r\n{"Close":8503.00,"DownTicks":152,"DownVolume":203,"High":8509.50,"Low":8502.00,"Open":8506.00,"Status":13,"TimeStamp":"\\/Date(1583531100000)\\/","TotalTicks":282,"TotalVolume":345,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":130,"UpVolume":142,"OpenInterest":0}\r\n{"Close":8494.00,"DownTicks":160,"DownVolume":206,"High":8505.75,"Low":8492.75,"Open":8503.25,"Status":13,"TimeStamp":"\\/Date(1583531400000)\\/","TotalTicks":275,"TotalVolume":346,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":115,"UpVolume":140,"OpenInterest":0}\r\n{"Close":8499.00,"DownTicks":136,"DownVolume":192,"High":8500.25,"Low":8492.25,"Open":8493.75,"Status":13,"TimeStamp":"\\/Date(1583531700000)\\/","TotalTicks":299,"TotalVolume":402,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":163,"UpVolume":210,"OpenInterest":0}\r\n{"Close":8501.75,"DownTicks":176,"DownVolume":314,"High":8508.25,"Low":8495.75,"Open":8498.50,"Status":536870941,"TimeStamp":"\\/Date(1583532000000)\\/","TotalTicks":340,"TotalVolume":510,"UnchangedTicks":0,"UnchangedVolume":0,"UpTicks":164,"UpVolume":196,"OpenInterest":0}\r\nEND'
"""
import pandas as pd
from datetime import datetime
import json

data = []
tss = ts.replace("b'","").replace("\r\nEND'","")
tss2 = tss.strip().split("\r\n")
for t in tss2:
    item = json.loads(t)
    epo = int(item['TimeStamp'].split('(')[1].split(')')[0])    
    eims = datetime.fromtimestamp(epo/1000)    
    item.update(TimeStamp=eims)
    data.append(item)
pd.DataFrame(data)

Вывод:

    Close   DownTicks   DownVolume  High    Low     Open    Status  TimeStamp   TotalTicks  TotalVolume     UnchangedTicks  UnchangedVolume     UpTicks     UpVolume    OpenInterest
0   8506.25     164     207     8508.25     8495.00     8496.75     13  2020-03-06 16:40:00     371     469     0   0   207     262     0
1   8503.00     152     203     8509.50     8502.00     8506.00     13  2020-03-06 16:45:00     282     345     0   0   130     142     0

et c. Вы можете удалить ненужные столбцы, изменить имена столбцов и т. Д.

...