前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >018:websocket实时动态数据爬取

018:websocket实时动态数据爬取

作者头像
李玺
发布2021-11-22 18:48:01
1.7K0
发布2021-11-22 18:48:01
举报
文章被收录于专栏:爬虫逆向案例

我们先看一下斗鱼直播的弹幕:

大家可以发现右下角在一直不断变化。

轮询和WebSocket:

Web 领域中,用于实现数据’实时’更新的手段有轮询和 WebSocket 这两种。

轮询指的是客户端按照一定时间间隔(如 1 秒)访问服务端接口,从而达到 ‘实时’ 的效果,虽然看起来数据像是实时更新的,但实际上它有一定的时间间隔,并不是真正的实时更新。轮询通常采用 拉 模式,由客户端主动从服务端拉取数据。

WebSocket 采用的是 推 模式,由服务端主动将数据推送给客户端,这种方式是真正的实时更新。

WebSocket:

WebSocket是一种在单个TCP连接上进行全双工通信的协议。

它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket 优点:

较少的控制开销:只需要进行一次握手,携带一次请求头信息即可,后续只传输数据即可,相比 HTTP 每次请求都携带请求头,WebSocket 非常省资源。

更强的实时性:由于服务器可以主动推送消息,这使得延迟变得可以忽略不计,相比 HTTP 轮询的时间间隔,WebSocket 可以在相同的时间内进行多次传输。

二进制支持:WebSocket 支持二进制帧,这意味着传输更节省。

案例分析:

先以莱特币官网 http://www.laiteb.com/ 实时数据为例

WebSocket 的握手只发生一次,所以如果需要通过浏览器开发者工具观察网络请求,则需要在打开页面的情况下,打开浏览器开发者工具,定位到 NewWork 选项卡,并输入或刷新当前页面,才能观察到 WebSocket 的握手请求和数据传输情况。这里以 Chrome 浏览器为例:

在开发者工具中提供了筛选功能,其中 WS 选项代表只显示 WebSocket 连接的网络请求。

这时候可以看到请求记录列表中有一条名为 realTime 的记录,鼠标左键点击它后,开发者工具会分为左右两栏,右侧列出本条请求记录的详细信息:

与 HTTP 请求不同的是,WebSocket 连接地址以 ws 或 wss 开头。连接成功的状态码不是 200,而是 101。

Headers 标签页记录的是 Request 和 Response 信息,而 Frames 标签页中记录的则是双方互传的数据,也是我们需要爬取的数据内容:

Frames 图中绿色箭头向上的数据是客户端发送给服务端的数据,橙色箭头向下的数据是服务端推送给客户端的数据。

从数据顺序中可以看到,客户端先发送: {"action":"ping"} 然后服务端才会推送信息(一直推送): {"action":"subscribe","group":"QuoteBin5m:14","success":true,"request":{"action":"subscribe","args":["QuoteBin5m:14"]}}

所以,从发起握手到获得数据的整个流程为:

使用aiowebsocket库爬取莱特网数据:

Python 库中用于连接 WebSocket 的有很多,但是易用、稳定的有 websocket-client(非异步)、websockets(异步)、aiowebsocket(异步)。

可以根据项目需求选择三者之一,这里介绍的是异步 WebSocket 连接客户端 aiowebsocket。

AioWebSocket是一个遵循 WebSocket 规范的 异步 WebSocket 客户端,相对于其他库它更轻、更快。

下面是代码: (代码为什么这个格式我也不清楚,官方文档里面是这么提供的 =。=)

代码语言:javascript
复制
import asyncio
import logging
from datetime import datetime
from aiowebsocket.converses import AioWebSocket

async def startup(uri):
    async with AioWebSocket(uri) as aws:
        converse = aws.manipulator
        # 客户端给服务端发送消息
        await converse.send('{"action":"subscribe","args":["QuoteBin5m:14"]}')
        while True:
            mes = await converse.receive()
            print('{time}-Client receive: {rec}'
                  .format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), rec=mes))

if __name__ == '__main__':
    remote = 'wss://api.bbxapp.vip/v1/ifcontract/realTime'
    try:
        asyncio.get_event_loop().run_until_complete(startup(remote))
    except KeyboardInterrupt as exc:
        logging.info('Quit.')

运行后: (可以看到数据已经不停的过来了)

我们再可以看下这个网站:(金十数据中心) https://datacenter.jin10.com/price

他的headers中Request Url是wss://开头的 右边正边疯狂的刷新数据,而使用的协议,正是 websocket

对于python下如何连接websocket ,网上有很多的文章,我这里就不用细说了,通常我们拿到这样的接口,都会本能去尝试直连看看,在进一步尝试之后,该端口的api会根据真实的请求变化 ,而且进一步的请求的cookie和key都会变化 ,看来直连的方式是行不通了,那没办法,只能走渲染的路了,selenium可以是可以,不过我们要尝试一下新的路线和方法,那就直接上chrome-headless

Headless Chrome指在headless模式下运行谷歌浏览器(以程序模式运行,没有界面),自从这玩意儿出来之后, phantomjs的作者就宣布不维护了。。。

直接使用docker 来安装chrome headless

代码语言:javascript
复制
docker run -d -p 9222:9222 --cap-add=SYS_ADMIN justinribeiro/chrome-headless

这样我们已经启用了一个chrome headless的服务,那如何使用呢,我们使用websocket 和chrome header less进行交互,不多说了,直接上代码吧

代码语言:javascript
复制
import json
import time
import requests
import websocket
 
request_id = 0
target_url = 'https://datacenter.jin10.com/price'

def get_websocket_connection():
    r = requests.get('http://10.10.2.42:9222/json') #这是开启chrome headless的机器地址
    if r.status_code != 200:
        raise ValueError("can not get the api ,please check if docker is ready")
 
    conn_api = r.json()[0].get('webSocketDebuggerUrl')
 
    return websocket.create_connection(conn_api)
 
def run_command(conn, method, **kwargs):
    global request_id
    request_id += 1
    command = {'method': method,
               'id': request_id,
               'params': kwargs}
    conn.send(json.dumps(command))
    #while True:
    msg = json.loads(conn.recv())
    if msg.get('id') == request_id:
        return msg
 
def get_element():
    conn = get_websocket_connection()
    msg = run_command(conn, 'Page.navigate', url=target_url)
    time.sleep(5)
    js = "var p = document.querySelector('.jin-pricewall_list-item_b').innerText ; p ;"
 
    for _ in range(20):
        time.sleep(1)
        msg = run_command(conn, 'Runtime.evaluate', expression=js)
        print(msg.get('result')['result']['value'])
 
if __name__ == '__main__':
    get_element()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/05/02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 轮询和WebSocket:
  • WebSocket:
  • WebSocket 优点:
  • 案例分析:
相关产品与服务
云开发 CLI 工具
云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档