首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
V2EX  ›  Python

请教下大家,用 Python 的 socket 模块请求 B 站有时返回乱码问题。

  •  
  •   Danpier · 31 天前 · 1653 次点击
    这是一个创建于 31 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码如下:

    import socket, ssl
    
    HOST = 'www.bilibili.com'
    
    sock = socket.socket()
    sock = ssl.wrap_socket(sock)
    sock.connect((HOST, 443))
    
    request = f'GET / HTTP/1.1\r\nHOST: {HOST}\r\nConnection: close\r\n\r\n'
    sock.send(request.encode())
    
    SIZE = 8192
    buffer = []
    while True:
        print(sock)
        data = sock.recv(SIZE)
        if not data:
            break
        buffer.append(data)
    data = b''.join(buffer)
    
    sock.close()
    data = data.split(b'\r\n\r\n', 1)[1]
    print(data.decode())
    

    GET 请求 B 站首页,返回的数据有时能正常解码为 UTF8,有时又会解码到一半报错提示无法解码,报错时我试着先把字节存到一个文件,然后按 UTF8 只解码前面的部分,可以正常解码。 代码跑多几遍就会出现(手动跑个 5、6 遍,应该跟反爬虫没关联吧),访问豆瓣 TOP250 电影( https://movie.douban.com/top250 )页面也会出现这个情况,豆瓣触发次数得跑多几遍,而且是固定位置报错,这个感觉很诡异,固定位置也不可能是传输数据丢了吧?这个问题困扰了我好几天了,望各位不吝赐教。

    17 回复  |  直到 2019-09-16 11:23:37 +08:00
        1
    ysc3839   31 天前 via Android
    发一下有问题的数据看看?
        2
    Danpier   31 天前
    @ysc3839
    报错提示:
    'utf-8' codec can't decode byte 0xe5 in position 34291: invalid continuation byte
        3
    ipwx   31 天前 via Android
    try: data.decode(errors='ignore')
        4
    Danpier   31 天前
    @ipwx 我是了解下问题出现的原因,忽视 error 这个我清楚。
        5
    ysc3839   31 天前 via Android
    @Danpier 我要看看数据,只有错误信息不知道是什么问题。
        6
    aquariumm   31 天前 via Android
    我猜是 brotli ?
        7
    Danpier   31 天前
    @ysc3839 V2EX
    链接: https://pan.baidu.com/s/17Abee6spBYuvS7r5EG4mXw 提取码: 8ku1
    贴下 header 部分:

    HTTP/1.1 200 OK
    Date: Sat, 14 Sep 2019 11:18:13 GMT
    Content-Type: text/html; charset=utf-8
    Transfer-Encoding: chunked
    Connection: close
    gear: 1
    vikingrCache: 60000
    Vikingr-Cache-TTL: 4376
    IDC: shjd
    Vary: Origin,Accept-Encoding
    Expires: Sat, 14 Sep 2019 11:18:43 GMT
    Cache-Control: max-age=30
    X-Cache-Webcdn: BYPASS from hw-gz3-webcdn-07

    报错位置在 34556,试了解码前 30000 没问题。
        8
    Danpier   31 天前
    @aquariumm request 参数没带 Accept-Encoding 也会接收到压缩数据吗?
        9
    gamexg   31 天前
    协议设置为 http 1.0 版本试试,
    Transfer-Encoding 之类功能都可能出问题
        10
    wwqgtxx   31 天前 via iPhone
    默默地问一下为啥不用 requests 或者 aiohttp,或者看看他们的源代码是怎么处理这种编码问题的
        11
    Danpier   31 天前
    @wwqgtxx 高级 API 能提供现成更好的实现方式,但很多问题就接触不到了
        12
    autogen   31 天前
    gzip 了吗?
        13
    ysc3839   30 天前
    @Danpier 看了数据,是 Transfer-Encoding: chunked 的问题。
    https://imququ.com/post/transfer-encoding-header-in-http.html

    另外,如无特殊需求,不建议自己实现 HTTP 客户端。
        14
    Danpier   30 天前
    @gamexg
    @ysc3839
    感谢答疑,几个出问题的网站确实都使用 Transfer-Encoding: chunked 来传输,用 HTTP 1.0 请求就不会使用分块编码。搞不懂请求带了 Connection: close 为什么还使用分块编码,另外数据拆分成多块是应用层组装数据时出了问题吗?
        15
    lolizeppelin   30 天前 via Android
    你的问题 应该去看 rfc 标准
        16
    gamexg   30 天前
    @Danpier #14 协议上面没要求 Connection: close 后就不能 Transfer-Encoding: chunked,所以服务器可以这么做。
    另外如果代码如主题所写,那么你并未移除每个块开头的标记信息,这个需要手工移除。

    参考文档:
    https://imququ.com/post/transfer-encoding-header-in-http.html
        17
    ysc3839   29 天前 via Android
    @Danpier 估计是避免连接意外断开的情况,没有长度的话客户端发现断开就会认为已经传完了。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4488 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 26ms · UTC 02:31 · PVG 10:31 · LAX 19:31 · JFK 22:31
    ♥ Do have faith in what you're doing.