RPC(Remote Procedure Call Protocol)是远程过程调用协议,一种不同于http协议的用于构建分布式系统。python提供xmlrpc库,下面是py2和py3的client类,可以带cookie请求数据。Show you the code:

python2

class CookieTransportRequest:
    """A Transport request method that retains cookies over its lifetime.

    The regular xmlrpclib transports ignore cookies. Which causes
    a bit of a problem when you need a cookie-based login, as with
    the XPLAN XMLRPC EDAI interface.

    So this is a helper for defining a Transport which looks for
    cookies being set in responses and saves them to add to all future
    requests.
    """
    def __init__(self, use_datetime=0):
        self._use_datetime = use_datetime
        self._connection = (None, None)
        self._extra_headers = []
        self.cookies = {}

    def extract_cookies(self, response):  # 生成cookie,具体根据应用rpc修改
        for header in response.msg.getallmatchingheaders("Set-Cookie"):
            val = header.split(':', 1)[1].strip()
            cookie = val.split(';', 1)[0].strip()
            cookiePair = cookie.split('=', 1)
            self.cookies[cookiePair[0].strip()] = cookiePair[1].strip()

    def get_cookies_header(self):
        cookieStr = ''
        for cookieName in self.cookies.keys():
            cookieStr = cookieStr + '%s=%s' % (cookieName, self.cookies[cookieName])
        return cookieStr

    def send_cookies(self, connection):
        cookieStr = ''
        for cookieName in self.cookies.keys():
            cookieStr = cookieStr + '%s=%s' % (cookieName, self.cookies[cookieName])
        if cookieStr != '':
            connection.putheader("Cookie", cookieStr)

    def login(self, host, homeUri, authUri, authBody, verbose=0):
        headers = {}
        self.verbose = verbose
        conn = self.make_connection(host)
        if verbose:
            conn.set_debuglevel(1)

        conn.request('GET', homeUri)

        try:
            response = conn.getresponse()
        except AttributeError:
            response = conn._conn.getresponse()

        self.extract_cookies(response) ##生成一个self.cookie
        response.read()  # 生成页面

        if response.status in (404,500,503,505,501):
            raise xmlrpclib.ProtocolError(host + homeUri, response.status,
                                          response.reason, response.msg.headers)
        #判断页面状态

        headers.clear()
        headers = {"Content-Type": "application/x-www-form-urlencoded","Accept": "text/plain","Connection":"keep-alive"}
        headers['Cookie'] = self.get_cookies_header()
        conn.request('POST', authUri, authBody, headers) ##进行登录
        try:
            response = conn.getresponse()
        except AttributeError:
            response = conn._conn.getresponse()

        self.extract_cookies(response)
        response.read()

        if response.status in (403,404,401,500,503,505,501):
            raise xmlrpclib.ProtocolError(host + homeUri, response.status,
                                          'Authenticate error', response.msg.headers)


        headers.clear()
        headers['Cookie'] = self.get_cookies_header() ##在header中加入cookie
        conn.request('GET', homeUri, None, headers)  ##请求这页面传入 cookie 与 header

        try:
            response = conn.getresponse()
        except AttributeError:
            response = conn._conn.getresponse()

        self.extract_cookies(response)  ##再次获取cookie
        response.read()


    def request(self, host, handler, request_body, verbose=0):
        self.verbose = verbose

        # issue XML-RPC request
        h = self.make_connection(host)
        if verbose:
            h.set_debuglevel(1)

        self.send_request(h, handler, request_body)
        self.send_host(h, host)
        self.send_cookies(h)
        self.send_user_agent(h)
        self.send_content(h, request_body)

        # Deal with differences between Python 2.4-2.6 and 2.7.
        # In the former h is a HTTP(S). In the latter it's a
        # HTTP(S)Connection. Luckily, the 2.4-2.6 implementation of
        # HTTP(S) has an underlying HTTP(S)Connection, so extract
        # that and use it.
        try:
            response = h.getresponse()
        except AttributeError:
            response = h._conn.getresponse()

        # Add any cookie definitions to our list.
        self.extract_cookies(response)

        if response.status != 200:
            raise xmlrpclib.ProtocolError(host + handler, response.status,
                                          response.reason, response.msg.headers)

#         if response.info().get('Content-Encoding') == 'gzip':
#             buf = StringIO(response.read())
#             f = gzip.GzipFile(fileobj=buf)
#             data = f.read()
#         else:
#             data = response.read()

        data = response.read()
        parser, unmarshaller = self.getparser()
        # import re, pickle
        # data = re.sub(u"[\x00-\x08\x0b-\x0c\x0e-\x1f]+", u"", data)
        # data = re.sub(u"[\n]+", u"", data)
        # print('\n', "re after:", data)
        # data = xmlrpclib.Binary(pickle.dumps(data)).data
        # import chardet
        # print chardet.detect(data)

        parser.feed(data)
        parser.close()

        return unmarshaller.close()

class CookieTransport(CookieTransportRequest, xmlrpclib.Transport):
    pass

class SafeCookieTransport(CookieTransportRequest, xmlrpclib.SafeTransport):
    pass



def getCookie():
    cookie = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
    AUTHBODY = urllib.urlencode(AUTHDATA)
    req = urllib2.Request(url='http://' + HOST + HOMEURL)
    opener.open(req)
    cookistr = ''
    for item in cookie:
        cookistr = cookistr + '%s=%s' % (item.name, item.value)
    headers = {}
    headers.clear()
    headers = {'Content-type': 'application/x-www-form-urlencoded', "Accept": "text/plain", "Connection": "keep-alive"}
    headers['Cookie'] = cookistr

    loginpage = urllib2.Request(url='http://' + HOST + AUTHURL, data=AUTHBODY, headers=headers)
    opener.open(loginpage)

    cookistr = ''
    for item in cookie:
        cookistr = cookistr + '%s=%s' % (item.name, item.value)
    headers = {}
    headers.clear()
    headers = {'Content-type': 'application/x-www-form-urlencoded', "Accept": "text/plain", "Connection": "keep-alive"}
    headers['Cookie'] = cookistr
    return headers


python3

class CookieTransportRequest:
    """A Transport request method that retains cookies over its lifetime.

    The regular xmlrpclib transports ignore cookies. Which causes
    a bit of a problem when you need a cookie-based login, as with
    the XPLAN XMLRPC EDAI interface.

    So this is a helper for defining a Transport which looks for
    cookies being set in responses and saves them to add to all future
    requests.
    """
    def __init__(self, use_datetime=0, use_builtin_types=False):
        self._use_datetime = use_datetime
        self._use_builtin_types = use_builtin_types
        self._connection = (None, None)
        self._extra_headers = []
        self.cookies = []

    def extract_cookies(self, response):
        print(response.msg.getallmatchingheaders("Set-Cookie"))
        print(response.msg.get_all("Set-Cookie"))   # 与py2的区别
        if not response.msg.getallmatchingheaders("Set-Cookie") and not response.msg.get_all("Set-Cookie"):
            print("\n extract_cookies", self.cookies)
            return self.cookies
        else:
            cookie_info = response.msg.get_all("Set-Cookie")
            if "SERVERID" in cookie_info[0]:
                return self.cookies
            self.cookies = []
            for header in cookie_info:
                self.cookies.append(header.split(";", 1)[0])
                print("\n extract_cookies", self.cookies)
                return self.cookies

    def get_cookies_header(self):
        cookieStr = ''
        for cookieName in self.cookies:
            cookieStr = cookieStr + '%s=%s' % (cookieName.split('=', 1)[0], cookieName.split('=', 1)[1])
        print("get_cookies", cookieStr)
        return cookieStr

    def send_headers(self, connection, headers):
        for key, val in headers:
            connection.putheader(key, val)

    def send_request(self, host, handler, request_body, debug):
        connection = self.make_connection(host)
        extra_headers = self._extra_headers[:]
        print("\nextra_headers", extra_headers)
        if extra_headers:
            if isinstance(extra_headers, dict):
                extra_headers = extra_headers.items()
                print("\nextra_headers", extra_headers)
            for key, value in extra_headers:
                connection.putheader(key, value)
        if debug:
            connection.set_debuglevel(1)
        if self.accept_gzip_encoding and gzip:
            connection.putrequest("POST", handler, skip_accept_encoding=True)
            extra_headers.append(("Accept-Encoding", "gzip"))
        else:
            connection.putrequest("POST", handler)
        extra_headers.append(("Cookie", self.get_cookies_header()))
        extra_headers.append(("User-Agent", self.user_agent))
        extra_headers.append(("Content-Type", "text/xml"))
        self.send_headers(connection, extra_headers)
        self.send_content(connection, request_body)
        return connection

    def login(self, host, homeUri, authUri, authBody, verbose=0):
        headers = {}
        conn = self.make_connection(host)
        if verbose:
            conn.set_debuglevel(1)

        conn.request('GET', homeUri)

        try:
            response = conn.getresponse()
        except AttributeError:
            response = conn._conn.getresponse()

        self.extract_cookies(response) ##生成一个self.cookies
        response.read()  # 生成页面
        print(response.status)

        if response.status in (404,500,503,505,501):
            raise xmlrpc.client.ProtocolError(host + homeUri, response.status,
                                          response.reason, response.msg.headers)
        #判断页面状态

        headers.clear()
        headers = {"Content-Type": "application/x-www-form-urlencoded","Accept": "text/plain","Connection":"keep-alive"}
        headers['Cookie'] = self.get_cookies_header()
        print(headers)
        conn.request('POST', authUri, authBody, headers) ##进行登录
        try:
            response = conn.getresponse()
        except AttributeError:
            response = conn._conn.getresponse()

        self.extract_cookies(response)
        response.read()
        print(response.status)

        if response.status in (403,404,401,500,503,505,501):
            raise xmlrpc.client.ProtocolError(host + homeUri, response.status,
                                          'Authenticate error', response.msg.headers)

        headers.clear()
        headers['Cookie'] = self.get_cookies_header() ##在header中加入cookie
        print(headers)
        conn.request('GET', homeUri, None, headers)  ##请求这页面传入 cookie 与 header

        try:
            response = conn.getresponse()
        except AttributeError:
            response = conn._conn.getresponse()

        self.extract_cookies(response)  ##再次获取cookie
        response.read()
        print("\nagain get", response.status)

    def request(self, host, handler, request_body, verbose=1):

        # issue XML-RPC request
        print(host, handler, request_body, self.cookies)
        # h = self.make_connection(host)
        # if verbose:
        #     h.set_debuglevel(1)

        h = self.send_request(host, handler, request_body, verbose)

        # Deal with differences between Python 2.4-2.6 and 2.7.
        # In the former h is a HTTP(S). In the latter it's a
        # HTTP(S)Connection. Luckily, the 2.4-2.6 implementation of
        # HTTP(S) has an underlying HTTP(S)Connection, so extract
        # that and use it.
        try:
            response = h.getresponse()
        except AttributeError:
            response = h._conn.getresponse()

        # Add any cookie definitions to our list.
        # self.extract_cookies(response)

        if response.status != 200:
            raise xmlrpc.client.ProtocolError(host + handler, response.status,
                                          response.reason, response.msg.headers)

        #         if response.info().get('Content-Encoding') == 'gzip':
        #             buf = StringIO(response.read())
        #             f = gzip.GzipFile(fileobj=buf)
        #             data = f.read()
        #         else:
        #             data = response.read()

        data = response.read().decode('utf-8')
        parser, unmarshaller = self.getparser()
        if not data:
            return parser.close()
        if verbose:
            print("body:", repr(data))
        # import re, pickle
        # data = re.sub(u"[\x00-\x08\x0b-\x0c\x0e-\x1f]+", u"", data)
        # data = re.sub(u"[\n]+", u"", data)
        # print('\n', "re after:", data)
        # data = xmlrpc.client.Binary(pickle.dumps(data)).data
        # import chardet
        # print chardet.detect(data)
        parser.feed(data)
        parser.close()

        return unmarshaller.close()


class CookieTransport(CookieTransportRequest, xmlrpc.client.Transport):
    pass


class SafeCookieTransport(CookieTransportRequest, xmlrpc.client.SafeTransport):
    pass


def getCookie():

    cookie = http.cookiejar.CookieJar()
    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie))
    AUTHBODY = urllib.parse.urlencode(AUTHDATA).encode(encoding='UTF8')
    req = urllib.request.Request(url='http://' + HOST + HOMEURL)
    opener.open(req)
    cookistr = ''
    for item in cookie:
        cookistr = cookistr + '%s=%s' % (item.name, item.value)
    headers = {}
    headers.clear()
    headers = {'Content-type': 'application/x-www-form-urlencoded', "Accept": "text/plain", "Connection": "keep-alive"}
    headers['Cookie'] = cookistr

    loginpage = urllib.request.Request(url='http://' + HOST + AUTHURL, data=AUTHBODY, headers=headers)
    opener.open(loginpage)  #### 408

    cookistr = ''
    for item in cookie:
        cookistr = cookistr + '%s=%s' % (item.name, item.value)
    headers = {}
    headers.clear()
    headers = {'Content-type': 'application/x-www-form-urlencoded', "Accept": "text/plain", "Connection": "keep-alive"}
    headers['Cookie'] = cookistr
    return headers