Sup*_*rah 0 html javascript python web-scraping
我看到有一些关于此的帖子,但每种情况显然都是独一无二的。我试图获取此页面图表背后的数据: https ://www.tradingview.com/symbols/NASDAQ-VOLI/
这是一个相当模糊的市场指数,并且无法通过雅虎获得,这是我通常查看的地方(特别web.DataReader是在Python中),并且这是似乎拥有全套每日价格的少数几个网站之一。
<script nonce="XL1oARYPz8X2tvqk">
window.__defaultsOverrides = {
'mainSeriesProperties.style': 3,
'mainSeriesProperties.areaStyle.priceSource': 'close',
'scalesProperties.lineColor': 'rgba( 76, 82, 94, 1)',
'scalesProperties.showSymbolLabels': false,
'scalesProperties.textColor': 'rgba( 76, 82, 94, 1)',
'scalesProperties.seriesLastValueMode': 0,
'paneProperties.topMargin': 13,
'paneProperties.legendProperties.showStudyArguments': false,
'paneProperties.legendProperties.showStudyTitles': false,
'paneProperties.legendProperties.showStudyValues': false,
'paneProperties.legendProperties.showSeriesTitle': false,
'paneProperties.legendProperties.showSeriesOHLC': true,
'paneProperties.legendProperties.showLegend': false,
};
</script>
Run Code Online (Sandbox Code Playgroud)
这就是与图表相关的元素,坦率地说,它在 Web 开发方面有点超出我的理解,因为它只是一个脚本标签(即,它不仅仅是图表元素的子元素 - 它是图表元素)。我尝试在 JS 文件中搜索 的随机数值XL1oARYPz8X2tvqk,但没有看到任何看起来会填充图表的内容。
我认为我能够在窗口对象中的某个位置找到图表数据,但我没有看到它。有没有一种简单的方法可以追踪到这一点?我知道我可以使用交互式刮刀,但看起来它必须比这更容易。
数据是从 websocket 连接检索的:
wss://data.tradingview.com/socket.io/websocket?from=symbols%2FNASDAQ-VOLI%2F
Run Code Online (Sandbox Code Playgroud)
您可以通过发送命令并从此 websocket 接收数据来获取这些数据。您可以查看从 Chrome 开发控制台接收和发送的所有消息:
格式是 JSON 对象流(每个响应可以是多个对象),带有一些前缀,例如~m~23+~m~. 因此有必要用正则表达式分割响应(中间的数字发生变化)
您在上面的屏幕截图中看到很多要发送的消息(绿色消息),但我们只对那些使用“图表会话令牌”的消息感兴趣,例如控制图表而不是报价的命令
在开头发送以下消息:
{"m": "set_data_quality", "p": ["low"]},
{"m": "set_auth_token", "p": ["unauthorized_user_token"]},
{"m":"chart_create_session","p":[chartSession,""]},
{"m":"resolve_symbol","p":[chartSession,"symbol_1","={\"symbol\":\"NASDAQ:VOLI\",\"adjustment\":\"splits\",\"session\":\"extended\"}"]},
{"m":"create_series","p":[chartSession,"s1","s1","symbol_1","D",300]},
{"m":"switch_timezone","p":[chartSession,"Etc/UTC"]},
{"m":"resolve_symbol","p":[chartSession,"symbol_2","={\"symbol\":\"NASDAQ:VOLI\",\"adjustment\":\"splits\",\"session\":\"extended\"}"]},
{"m":"modify_series","p":[chartSession,"s1","s2","symbol_2","D,12M"]},
Run Code Online (Sandbox Code Playgroud)
之后,您会收到一条响应,其中包含一条timescale_update包含图表数据等内容的有价值的消息
以下脚本启动 websocket 连接,发送获取图表数据所需的初始消息,并使用matplotlib构建一个保存为 png 的图表:
import json
import websockets
import urllib
import asyncio
import re
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
wsParams = {
"from": "symbols/NASDAQ-VOLI/"
}
websocketUri = f"wss://data.tradingview.com/socket.io/websocket?{urllib.parse.urlencode(wsParams)}"
result = []
chartSession = "cs_Dj1BV8ochLL0"
initMessages = [
{"m": "set_data_quality", "p": ["low"]},
{"m": "set_auth_token", "p": ["unauthorized_user_token"]},
{"m":"chart_create_session","p":[chartSession,""]},
{"m":"resolve_symbol","p":[chartSession,"symbol_1","={\"symbol\":\"NASDAQ:VOLI\",\"adjustment\":\"splits\",\"session\":\"extended\"}"]},
{"m":"create_series","p":[chartSession,"s1","s1","symbol_1","D",300]},
{"m":"switch_timezone","p":[chartSession,"Etc/UTC"]},
{"m":"resolve_symbol","p":[chartSession,"symbol_2","={\"symbol\":\"NASDAQ:VOLI\",\"adjustment\":\"splits\",\"session\":\"extended\"}"]},
{"m":"modify_series","p":[chartSession,"s1","s2","symbol_2","D,12M"]},
]
def strip(text):
noDataReg = re.match('~m~\d+~m~~h~\d+', text, re.MULTILINE)
if not noDataReg:
dataReg = re.split('~m~\d+~m~', text)
return [json.loads(t) for t in dataReg if t]
return []
def unstrip(text):
return f"~m~{len(text)-8}~m~{json.dumps(text)}"
async def init(websocket):
for m in initMessages:
await websocket.send(unstrip(m))
async def startReceiving(websocket):
data = await websocket.recv()
print(strip(data))
await init(websocket)
while(True):
data = await websocket.recv()
payloads = strip(data)
for p in payloads:
if p["m"] == "timescale_update":
dates = [
datetime.fromtimestamp(t["v"][0])
for t in p["p"][1]["s1"]["s"]
]
values = [
t["v"][4]
for t in p["p"][1]["s1"]["s"]
]
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%d/%m/%Y'))
plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=25))
plt.plot(dates, values)
plt.gcf().autofmt_xdate()
plt.ylabel('VOLI Index Chart')
plt.xlabel('Date')
plt.savefig("voli.png")
print(payloads)
async def websocketConnect():
async with websockets.client.connect(websocketUri, extra_headers= {
"Origin": "https://www.tradingview.com"
}) as websocket:
print(f'started websocket')
await startReceiving(websocket)
asyncio.get_event_loop().run_until_complete(websocketConnect())
Run Code Online (Sandbox Code Playgroud)
在 repl.it 上尝试一下(没有 matplotlib 部分)
以及生成的图表:
一些注意事项:
为了成功连接到 websocket 服务器,您需要发送Origin具有正确值的标头,否则将返回 403
图表会话令牌在这里是硬编码的,但它可以是任何东西,它似乎是在网站上随机生成的(使用正则表达式模式)
我已经删除了所有有关报价的 websocket 消息,您需要添加此类消息以接收有关“实时”值更改的通知(将添加到初始化消息中):
{"m":"quote_create_session","p":["qs_QrddDPrS65gC"]}
{"m":"quote_add_symbols","p":["qs_QrddDPrS65gC","NASDAQ:VOLI",{"flags":["force_permission"]}]}
Run Code Online (Sandbox Code Playgroud)
请注意,这quote_create_session对于新的会话令牌(!= 来自图表会话令牌)是必需的。然后您将通过 websocket 收到通知
如果您想接收通知,请注意,如果您在 x 时间段内没有发送任何内容,则有一个保持活动状态,它会自动关闭 websocket。您只需要定期发送以下命令:
~m~4~m~~h~1
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2697 次 |
| 最近记录: |