爬虫之websocket数据爬取

收集了大家的问题。我又重新写了一篇websocket的代码,并添加了注释,在文章最后。希望可以解决大家遇到的问题~

websocket是最近开发很常用的技术之一,他可以一直保持着连接不断,但是你的页面还可以继续展示其它任务,很适用于直播时候的弹幕等。这个是我自己的基础理解,详细理解大家可以参考:https://segmentfault.com/a/1190000013149749

我觉得针对websocket的数据爬取,一定要有逆向思维,首先找到数据,然后去倒推这个流程,进而掌握数据传送的全过程。而且针对websocket数据爬取,有一个很好的框架大家可以使用


import time
import json
import pandas as pd
import requests
import websocket
from requests.adapters import HTTPAdapter
import time

try:
    import thread
except ImportError:
    import _thread as thread


class websocket_class :
    def __init__(self):
       pass
    
    #这里就是websocket爬虫的核心,发送请求,接收数据并做最后处理,
    def on_message(self,ws, message):
        pass

    def on_error(self,ws, error):
        print(error)
    #关闭websocket长连接
    def on_close(self,ws):
        print("关闭连接")

	#程序运行第一步
    def on_open(self,ws):
        def run(*args):
          	#这里面就是写大家倒退出来页面请求第一步的代码
          	pass
        thread.start_new_thread(run, ())


if __name__ == "__main__":
    header = {
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9,',
        'Cache-Control': 'no-cache',
        'Connection': 'Upgrade',
        'Cookie': cookie,
        'Host': 'ws-nextbi.yushanfang.com',
        'Origin': 'https://nextbi.yushanfang.com',
        'Pragma': 'no-cache',
        'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
        #这个参数要进行实时修改
        'Sec-WebSocket-Key': 'QBn6rnK29DZL6BC6+O2TRA==',
        'Sec-WebSocket-Version': '13',
        'Upgrade': 'websocket',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
    }

    websocket.enableTrace(True)
    websocket_obj = websocket_class(cookie, appId, cateId,filename)
    ws = websocket.WebSocketApp("wss://ws-nextbi.yushanfang.com/",
                                on_message = websocket_obj.on_message,
                                on_error = websocket_obj.on_error,
                                on_close = websocket_obj.on_close,
                                header=header)

    ws.on_open = websocket_obj.on_open
    ws.run_forever()

首先大家可以看到下图,就证明此数据是websocket传输
在这里插入图片描述websocket 页面w
大家可以看到我标红的地方有两个箭头,绿色的就是我们需要模拟的请求,红色朝下的就是请求对应的数据,那么问题来了,页面上那么多请求和接收,我们如何知道哪个请求对应哪个数据呢?

这个rid就是我们找一对请求和接受的依据。大家肯定注意到,这个rid和时间戳很类似,没错这就是一个13位的时间戳,和随机数组合而成的

randomID = str(int(time.time()*1000))+str(self.count).zfill(3)

大家可以依据我上面说的这些,结合自己的网站写爬虫代码。

#这是我的一部分请求代码
 randomID = str(int(time.time()*1000))+str(self.count).zfill(3)

 self.targetID['tagTitle'][randomID]= self.targetID['targetSecondID'][subrid]

 sendMessage = {"method":"/iWidget/list","headers":{"rid":randomID,"type":"PULL"},"body":{"args":{"sheetId":message['body'],"appId":self.appId}}}

 ws.send(json.dumps(sendMessage))

我遇到的问题:
1.爬取的时候总是有一大串的报红
在这里插入图片描述
我的理解是发送的请求并没有接受的数据,因为rid是根据当前的时间在不停的生成时间戳,所以会出现一些时间戳并没有匹配的数据,当人大家可以看到白色的字体就是我接受的数据。

2.无法批量拉取数据,因为websocket是长连接,批量拉取的话,如果爬取第二个数据,第一个数据的长连接总是无法关掉,导致数据重复爬取,我有进行强制关闭,依然无法批量。

#下面我放一份我自己写的一个关于websocket 抓取数据的代码。

import websocket
from requests.adapters import HTTPAdapter


from mybaseCode import *

try:
    import thread
except ImportError:
    import _thread as thread


class websocket_class :

    count =0

    sheetIds = [] #获取所有的标签ID

    targetID = {}


    targetID['getDataOnWidgetV2'] = {}
    targetID['targetSecondID'] = {}
    targetID['tagTitle'] = {} #标签名称
    targetID['tagTitleTT'] = {}  # 标签名称

    #需要定期去修改

    newDF = pd.DataFrame()

    def __init__(self,cookie, appId, brandId,date):
        # 配置requests
        self.s = requests.Session()
        self.NETWORK_STATUS = False
        self.REQUEST_TIMEOUT = False
        # 配置requests超时重试
        self.s.mount('http://', HTTPAdapter(max_retries=3))
        self.s.mount('https://', HTTPAdapter(max_retries=3))
        self.date=date
        self.appId = appId
        self.brandId = brandId
        self.insertCookie(cookie)
        self.getsheetIds()
        self.n=0
        self.final=pd.DataFrame(columns=['类目','渠道','时间',
                                         '销售金额-本品牌', '销售金额同比-本品牌',
                                         '购买人数-本品牌','购买人数同比-本品牌',
                                         '客单价-本品牌','客单价同比-本品牌',
                                         '人均购买叶子类目数-本品牌', '人均购买叶子类目数同比-本品牌',
                                         '新进叶子类目数-本品牌','新进叶子类目数同比-本品牌'
        ])

    #这个是我封装的cooke请求
    def insertCookie(self,cookie):
        # 读取cookie
        cookies = []
        try:
            for line in cookie.split(';'):
                name, value = line.strip().split('=', 1)
                cookies.append({'name': name, 'value': value})
        except ValueError:
            print('cookie格式错误!')
            return {'errCode': -1, 'errMsg': 'cookie格式错误!'}

        # cookie注入到requests.Session
        for cookie in cookies:
            if cookie['name'] == '_tb_token_':
                self.x_csrf_token = cookie['value']
            self.s.cookies.set(cookie['name'], cookie['value'])

    #这里是为了爬虫统一封装的参数
    def requests_method(self, url):

        try:
            result = self.s.get(url,
                                headers={
                                    'accept-encoding': 'gzip, deflate, br',
                                    'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,la;q=0.6',
                                    'cache-control': 'no-cache',
                                    'pragma':'no-cache',
                                    'referer':'https://databank.tmall.com/',
                                    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
                                }
                    ).text
            return result
        except Exception as e:
            print(e)
            return False

    #这个自定义函数是我发现websocket请求之前有一些参数我需要通过这个请求拿到
    def getsheetIds(self):
        url='https://strategy.tmall.com/api/scapi?path=/api/v1/category/strategy/listRelation&brandId='+self.brandId
        sendPackage = self.requests_method(url)
        res = json.loads(sendPackage)
        self.tagSheetIds = {}
        for item in res['data']:

            if item['children'] == None:
                self.tagSheetIds[item['cateId']] = item['cateFullName']
            else:
                self.tagSheetIds[item['cateId']] = item['cateFullName']
                for childrenId in item['children']:
                    self.tagSheetIds[childrenId['cateId']] = childrenId['cateFullName']



    #这里其实有点自调函数的意思,因为所有通过ws.send()方法接收的message都会到这里,
    # 所以你就需要通过下面的rid取判断,此时接收的message到哪一层(或者说是哪个请求反馈的结果。
    def on_message(self,ws, message):
        print('---------------进入方法-----------------------')
        print(message)

        message = json.loads(message)
        subrid = message['
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值