欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python如何爬取實(shí)時(shí)變化的WebSocket數(shù)據(jù)的方法

 更新時(shí)間:2019年03月09日 11:26:22   作者:AsyncIns  
這篇文章主要介紹了Python如何爬取實(shí)時(shí)變化的WebSocket數(shù)據(jù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、前言

作為一名爬蟲(chóng)工程師,在工作中常常會(huì)遇到爬取實(shí)時(shí)數(shù)據(jù)的需求,比如體育賽事實(shí)時(shí)數(shù)據(jù)、股市實(shí)時(shí)數(shù)據(jù)或幣圈實(shí)時(shí)變化的數(shù)據(jù)。如下圖:

Web 領(lǐng)域中,用于實(shí)現(xiàn)數(shù)據(jù)'實(shí)時(shí)'更新的手段有輪詢和 WebSocket 這兩種。輪詢指的是客戶端按照一定時(shí)間間隔(如 1 秒)訪問(wèn)服務(wù)端接口,從而達(dá)到 '實(shí)時(shí)' 的效果,雖然看起來(lái)數(shù)據(jù)像是實(shí)時(shí)更新的,但實(shí)際上它有一定的時(shí)間間隔,并不是真正的實(shí)時(shí)更新。輪詢通常采用 拉 模式,由客戶端主動(dòng)從服務(wù)端拉取數(shù)據(jù)。

WebSocket 采用的是 推 模式,由服務(wù)端主動(dòng)將數(shù)據(jù)推送給客戶端,這種方式是真正的實(shí)時(shí)更新。

二、什么是 WebSocket

WebSocket是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。它使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

WebSocket 優(yōu)點(diǎn)

  • 較少的控制開(kāi)銷:只需要進(jìn)行一次握手,攜帶一次請(qǐng)求頭信息即可,后續(xù)只傳輸數(shù)據(jù)即可,相比 HTTP 每次請(qǐng)求都攜帶請(qǐng)求頭,WebSocket 非常省資源。
  • 更強(qiáng)的實(shí)時(shí)性:由于服務(wù)器可以主動(dòng)推送消息,這使得延遲變得可以忽略不計(jì),相比 HTTP 輪詢的時(shí)間間隔,WebSocket 可以在相同的時(shí)間內(nèi)進(jìn)行多次傳輸。
  • 二進(jìn)制支持:WebSocket 支持二進(jìn)制幀,這意味著傳輸更節(jié)省。
  • ……

爬蟲(chóng)面對(duì) HTTP 和 WebSocket

Python 中的網(wǎng)絡(luò)請(qǐng)求庫(kù)非常多,Requests 是最常用的請(qǐng)求庫(kù)之一,它可以模擬發(fā)送網(wǎng)絡(luò)請(qǐng)求。但是這些請(qǐng)求都是基于 HTTP 協(xié)議的。在面對(duì) WebSocket 的時(shí)候 Requests 就發(fā)揮不料作用了,必須使用能夠連接 WebSocket 的庫(kù)。

三、爬取思路

這里以萊特幣官網(wǎng) http://www.laiteb.com/ 實(shí)時(shí)數(shù)據(jù)為例。WebSocket 的握手只發(fā)生一次,所以如果需要通過(guò)瀏覽器開(kāi)發(fā)者工具觀察網(wǎng)絡(luò)請(qǐng)求,則需要在打開(kāi)頁(yè)面的情況下,打開(kāi)瀏覽器開(kāi)發(fā)者工具,定位到 NewWork 選項(xiàng)卡,并輸入或刷新當(dāng)前頁(yè)面,才能觀察到 WebSocket 的握手請(qǐng)求和數(shù)據(jù)傳輸情況。這里以 Chrome 瀏覽器為例:

在開(kāi)發(fā)者工具中提供了篩選功能,其中 WS 選項(xiàng)代表只顯示 WebSocket 連接的網(wǎng)絡(luò)請(qǐng)求。

這時(shí)候可以看到請(qǐng)求記錄列表中有一條名為 realTime 的記錄,鼠標(biāo)左鍵點(diǎn)擊它后,開(kāi)發(fā)者工具會(huì)分為左右兩欄,右側(cè)列出本條請(qǐng)求記錄的詳細(xì)信息:

與 HTTP 請(qǐng)求不同的是,WebSocket 連接地址以 ws 或 wss 開(kāi)頭。連接成功的狀態(tài)碼不是 200,而是 101。

Headers 標(biāo)簽頁(yè)記錄的是 Request 和 Response 信息,而 Frames 標(biāo)簽頁(yè)中記錄的則是雙方互傳的數(shù)據(jù),也是我們需要爬取的數(shù)據(jù)內(nèi)容:

Frames 圖中綠色箭頭向上的數(shù)據(jù)是客戶端發(fā)送給服務(wù)端的數(shù)據(jù),橙色箭頭向下的數(shù)據(jù)是服務(wù)端推送給客戶端的數(shù)據(jù)。

從數(shù)據(jù)順序中可以看到,客戶端先發(fā)送:

{"action":"subscribe","args":["QuoteBin5m:14"]}

然后服務(wù)端才會(huì)推送信息(一直推送):

復(fù)制代碼 代碼如下:
{"group":"QuoteBin5m:14","data":[{"low":"55.42","high":"55.63","open":"55.42","close":"55.59","last_price":"55.59","avg_price":"55.5111587372932781077","volume":"40078","timestamp":1551941701,"rise_fall_rate":"0.0030674846625766871","rise_fall_value":"0.17","base_coin_volume":"400.78","quote_coin_volume":"22247.7621987324"}]}

所以,從發(fā)起握手到獲得數(shù)據(jù)的整個(gè)流程為:

那么,現(xiàn)在問(wèn)題來(lái)了:

  • 握手怎么弄?
  • 連接保持怎么弄?
  • 消息發(fā)送和接收怎么弄?
  • 有什么庫(kù)可以輕松實(shí)現(xiàn)嗎?

四、aiowebsocket

Python 庫(kù)中用于連接 WebSocket 的有很多,但是易用、穩(wěn)定的有 websocket-client(非異步)、websockets(異步)、aiowebsocket(異步)。

可以根據(jù)項(xiàng)目需求選擇三者之一,今天介紹的是異步 WebSocket 連接客戶端 aiowebsocket。其 Github 地址為: https://github.com/asyncins/aiowebsocket 。

ReadMe中介紹到: AioWebSocket是一個(gè)遵循 WebSocket 規(guī)范的 異步 WebSocket 客戶端,相對(duì)于其他庫(kù)它更輕、更快。

它的安裝和其他庫(kù)一樣簡(jiǎn)單,使用 pip install aiowebsocket 即可。安裝好后,我們可以根據(jù) ReadMe 中提供的示例代碼來(lái)測(cè)試:

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
  message = b'AioWebSocket - Async WebSocket Client'
  while True:
   await converse.send(message)
   print('{time}-Client send: {message}'
     .format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), message=message))
   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 = 'ws://echo.websocket.org'
 try:
  asyncio.get_event_loop().run_until_complete(startup(remote))
 except KeyboardInterrupt as exc:
  logging.info('Quit.')

運(yùn)行后的結(jié)果輸出為:

2019-03-07 15:43:55-Client send: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:55-Client receive: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:55-Client send: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:56-Client receive: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:56-Client send: b'AioWebSocket - Async WebSocket Client'
……

send 表示客戶端向服務(wù)端發(fā)送的消息

recive 表示服務(wù)端向客戶端推送的消息

五、編碼獲取數(shù)據(jù)

回到這一次的爬取需求,目標(biāo)網(wǎng)站是萊特幣官網(wǎng):

從剛才的網(wǎng)絡(luò)請(qǐng)求記錄中,我們得知目標(biāo)網(wǎng)站的 WebSocket 地址為: wss://api.bbxapp.vip/v1/ifcontract/realTime ,從地址中可以看出目標(biāo)網(wǎng)站使用的是 wss,也就是 ws 的安全版,它們的關(guān)系跟 HTTP/HTTPS 一樣。aiowebsocket 會(huì)自動(dòng)處理并識(shí)別 ssl,所以我們并不需要作額外的操作,只需要將目標(biāo)地址賦值給連接 uri 即可:

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
  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.')

運(yùn)行代碼后觀察輸出,你會(huì)發(fā)現(xiàn)什么都沒(méi)有發(fā)生。既沒(méi)有內(nèi)容輸出,也沒(méi)有斷開(kāi)連接,程序一直在運(yùn)行,但是什么都沒(méi)有:

這是為什么呢?

是對(duì)方不接受我方的請(qǐng)求嗎?

還是有什么反爬蟲(chóng)限制呢?

實(shí)際上,剛才的流程圖可以解釋這個(gè)問(wèn)題:

整個(gè)流程中有一步是需要客戶端給服務(wù)端發(fā)送指定的消息,服務(wù)端驗(yàn)證后才會(huì)不停推送數(shù)據(jù)。所以,應(yīng)該在消息讀取前、握手連接后加上消息發(fā)送的代碼:

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
  # 客戶端給服務(wù)端發(fā)送消息
  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.')

保存后運(yùn)行,就會(huì)看到數(shù)據(jù)源源不斷的推送過(guò)來(lái):

到這里,爬蟲(chóng)就能夠獲取到想要的數(shù)據(jù)了。

aiowebsocket 做了什么

代碼不長(zhǎng),使用的時(shí)候只需要將目標(biāo)網(wǎng)站 WebSocket 地址填入,然后按照流程發(fā)送數(shù)據(jù)即可,那么 aiowebsocket 在這個(gè)過(guò)程中做了什么呢?

  • 首先,aiowebsocket 根據(jù) WebSocket 地址,向指定的服務(wù)端發(fā)送握手請(qǐng)求,并校驗(yàn)握手結(jié)果。
  • 然后,在確認(rèn)握手成功后,將數(shù)據(jù)發(fā)送給服務(wù)端。
  • 整個(gè)過(guò)程中為了保持連接不斷開(kāi),aiowebsocket 會(huì)自動(dòng)與服務(wù)端響應(yīng) ping pong。
  • 最后,aiowebsocket 讀取服務(wù)端推送的消息

【奎因:】如果你認(rèn)為 aiowebsocket 幫助了你,那么請(qǐng)你到 Github https://github.com/asyncins/aiowebsocket 上給一個(gè) Star。如果在使用當(dāng)中發(fā)現(xiàn)問(wèn)題或者希望給 aiowebsocket 提建議,那么也可以到 Github 上提出。只要你提出建議,就一定能夠幫助 aiowebsocket 變的更好,而 aiowebsocket 也能夠繼續(xù)為你服務(wù)。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python 相對(duì)路徑報(bào)錯(cuò):"No such file or directory"'原因及解決方法

    Python 相對(duì)路徑報(bào)錯(cuò):"No such file or 

    如果你取相對(duì)路徑不是在主文件里,可能就會(huì)有相對(duì)路徑問(wèn)題:"No such file or directory",由于python 的相對(duì)路徑,相對(duì)的都是主文件所以會(huì)出現(xiàn)Python 相對(duì)路徑報(bào)錯(cuò),今天小編給大家?guī)?lái)了完美解決方案,感興趣的朋友一起看看吧
    2023-02-02
  • Python 實(shí)現(xiàn)國(guó)產(chǎn)SM3加密算法的示例代碼

    Python 實(shí)現(xiàn)國(guó)產(chǎn)SM3加密算法的示例代碼

    這篇文章主要介紹了Python 實(shí)現(xiàn)國(guó)產(chǎn)SM3加密算法的示例代碼,幫助大家更好的理解和學(xué)習(xí)密碼學(xué),感興趣的朋友可以了解下
    2020-09-09
  • django框架自定義模板標(biāo)簽(template tag)操作示例

    django框架自定義模板標(biāo)簽(template tag)操作示例

    這篇文章主要介紹了django框架自定義模板標(biāo)簽(template tag)操作,結(jié)合實(shí)例形式分析了Django框架自定義模板標(biāo)簽原理、操作步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-06-06
  • Python Pytorch深度學(xué)習(xí)之圖像分類器

    Python Pytorch深度學(xué)習(xí)之圖像分類器

    今天小編就為大家分享一篇關(guān)于Pytorch圖像分類器的文章,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-10-10
  • python獲取響應(yīng)某個(gè)字段值的3種實(shí)現(xiàn)方法

    python獲取響應(yīng)某個(gè)字段值的3種實(shí)現(xiàn)方法

    這篇文章主要介紹了python獲取響應(yīng)某個(gè)字段值的3種實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-04-04
  • Python lxml解析HTML并用xpath獲取元素的方法

    Python lxml解析HTML并用xpath獲取元素的方法

    今天小編就為大家分享一篇Python lxml解析HTML并用xpath獲取元素的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • python使用socket高效傳輸視頻數(shù)據(jù)幀(連續(xù)發(fā)送圖片)

    python使用socket高效傳輸視頻數(shù)據(jù)幀(連續(xù)發(fā)送圖片)

    本文主要介紹了python使用socket高效傳輸視頻數(shù)據(jù)幀(連續(xù)發(fā)送圖片),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Python對(duì)象的生命周期源碼學(xué)習(xí)

    Python對(duì)象的生命周期源碼學(xué)習(xí)

    這篇文章主要為大家介紹了Python對(duì)象的生命周期源碼學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Python中協(xié)程coroutine適用場(chǎng)景分析

    Python中協(xié)程coroutine適用場(chǎng)景分析

    多線程中可能出現(xiàn)多個(gè)線程爭(zhēng)搶變量,所以變量需要加鎖;協(xié)程中任一時(shí)刻都只有一個(gè)線程,所以變量不需要加鎖,這篇文章主要介紹了Python中協(xié)程(coroutine)詳解,需要的朋友可以參考下
    2024-04-04
  • PyQt+socket實(shí)現(xiàn)遠(yuǎn)程操作服務(wù)器的方法示例

    PyQt+socket實(shí)現(xiàn)遠(yuǎn)程操作服務(wù)器的方法示例

    這篇文章主要介紹了PyQt+socket實(shí)現(xiàn)遠(yuǎn)程操作服務(wù)器的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評(píng)論