python-2.7 - python SSLError ("bad handshake: SysCallError(-1, ' 意外的 EOF')",),))

标签 python-2.7 beautifulsoup openssl python-requests

我正在抓取这个 aspx 网站 https://gra206.aca.ntu.edu.tw/Temp/W2.aspx?Type=2 .

根据需要,我必须解析 __VIEWSTATE __事件验证同时发送 发帖 要求。现在我想发送一个 获取 首先请求拥有这两个值,然后再解析。

但是,我已经尝试多次发送 获取 要求。结果总是抛出此错误消息:

requests.exceptions.SSLError: HTTPSConnectionPool(host='gra206.aca.ntu.edu.tw', port=443): Max retries exceeded with url: /Temp/W2.aspx?Type=2 (Caused by SSLError(SSLError("bad handshake: SysCallError(-1, 'Unexpected EOF')",),))



我试过了:
  • 升级 OpenSSL
  • 下载请求[安全]

  • 但是,它们都不起作用。

    我目前正在使用:
    env:
    python 2.7
    bs4 4.6.0
    request 2.18.4
    openssl 1.0.2n
    

    这是我的代码:
    import requests
    from   bs4 import BeautifulSoup
    
    with requests.Session() as s:
        s.auth = ('user', 'pass')
        s.headers.update({'x-test': 'true'})
        url = 'https://gra206.aca.ntu.edu.tw/Temp/W2.aspx?Type=2'
        r = s.get(url, headers={'x-test2': 'true'})
    
    soup = BeautifulSoup(r.content, 'lxml')
    viewstate  = soup.find('input', {'id': '__VIEWSTATE'         })['value']
    validation = soup.find('input', {'id': '__EVENTVALIDATION'   })['value']  
    print viewstate, generator, validation
    

    最佳答案

    我也在为它寻找解决方案。一些站点已弃用 TLSv1.0 并且 Requests + Openssl(在 Windows 7 上)难以与此类对等主机建立握手。 Wireshark 日志显示 TLSv1 Client Hello 是由客户端发出的,但主机没有正确回答。此错误随着错误消息请求显示而传播。即使使用最新的 Openssl/pyOpenssl/Requests 并在 Py3.6/2.7.12 上尝试过,也没有运气。有趣的是,当我将 url 替换为“google.com”等其他网址时,日志显示 TLSv1.2 Hello 已发出并由主机响应。请查看图片 tlsv1
    tlsv1.2 .
    显然,客户端具有 TLSv1.2 功能,但为什么在前一种情况下使用 v1.0 Hello?

    [编辑]
    我在之前的陈述中错了。 Wireshark 将未完成的 TLSv1.2 HELLO 误解为 TLSv1。在深入研究之后,我发现这些主机期待纯 TLSv1,而不是来自 TLSv1.2 的 TLSv1 回退。由于与 Chrome 的日志相比,Openssl 在 Hello 扩展字段(可能支持的版本)中缺少某些字段。我找到了解决方法。 1.强制使用TLSv1协商。 2. 将默认密码套件更改为 py3.4 样式以重新启用 3DES。

    import ssl
    import requests
    from requests.adapters import HTTPAdapter
    from requests.packages.urllib3.poolmanager import PoolManager
    #from urllib3.poolmanager import PoolManager
    from requests.packages.urllib3.util.ssl_ import create_urllib3_context
    
        # py3.4 default
    CIPHERS = (
        'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
        'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
        '!eNULL:!MD5'
    )
    
    class DESAdapter(HTTPAdapter):
        """
        A TransportAdapter that re-enables 3DES support in Requests.
        """
        def create_ssl_context(self):
            #ctx = create_urllib3_context(ciphers=FORCED_CIPHERS)
            ctx = ssl.create_default_context()
            # allow TLS 1.0 and TLS 1.2 and later (disable SSLv3 and SSLv2)
            #ctx.options |= ssl.OP_NO_SSLv2
            #ctx.options |= ssl.OP_NO_SSLv3 
            #ctx.options |= ssl.OP_NO_TLSv1
            ctx.options |= ssl.OP_NO_TLSv1_2
            ctx.options |= ssl.OP_NO_TLSv1_1
            #ctx.options |= ssl.OP_NO_TLSv1_3
            ctx.set_ciphers( CIPHERS )
            #ctx.set_alpn_protocols(['http/1.1', 'spdy/2'])
            return ctx
    
        def init_poolmanager(self, *args, **kwargs):
            context = create_urllib3_context(ciphers=CIPHERS)
            kwargs['ssl_context'] = self.create_ssl_context()
            return super(DESAdapter, self).init_poolmanager(*args, **kwargs)
    
        def proxy_manager_for(self, *args, **kwargs):
            context = create_urllib3_context(ciphers=CIPHERS)
            kwargs['ssl_context'] = self.create_ssl_context()
            return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)
    
    tmoval=10
    proxies={}
    hdr = {'Accept-Language':'zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4', 'Cache-Control':'max-age=0', 'Connection':'keep-alive', 'Proxy-Connection':'keep-alive', #'Cache-Control':'no-cache', 'Connection':'close',
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36',
            'Accept-Encoding':'gzip,deflate,sdch','Accept':'*/*'}
    ses = requests.session()
    ses.mount(url, DESAdapter())
    
    response = ses.get(url, timeout=tmoval, headers = hdr, proxies=proxies)
    

    [编辑2]
    当您的 HTTPS url 包含任何大写字母时,补丁将无法工作。您需要将它们反转为小写。堆栈 requests/urllib3/openssl 中的某些未知导致补丁逻辑恢复为其默认的 TLS1.2 方式。

    [编辑3]
    来自 http://docs.python-requests.org/en/master/user/advanced/

    The mount call registers a specific instance of a Transport Adapter to a prefix. Once mounted, any HTTP request made using that session whose URL starts with the given prefix will use the given Transport Adapter.



    因此,要使所有 HTTPS 请求包括那些由服务器重定向以使用新适配器的请求,必须将此行更改为:
    ses.mount('https://', DESAdapter())
    

    它以某种方式解决了上面提到的大写问题。

    关于python-2.7 - python SSLError ("bad handshake: SysCallError(-1, ' 意外的 EOF')",),)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49165989/

    相关文章:

    python - 从文件中读取几列

    python - 无法使用beautifulsoup提取表数据

    objective-c - Shell 脚本调用错误

    java - 使用java解密OpenSSL加密数据

    java - 如何安装antlr4?

    python - 每 3 个数字将列表中的数字相加

    python - 如何在 python 中修改 html 树?

    python - BeautifulSoup 从 find 中获取属性

    SSL_accept() 失败,返回 "SSL routines:SSL_GET_NEW_SESSION:ssl session id callback failed'

    python - 为什么更新一个字典对象会影响其他对象?