You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python Shareplum访问本地SharePoint文件遇JSON解析错误求助

解决SharePoint 2013中Python脚本访问文件夹时的JSONDecodeError问题

问题现象

我有一个SharePoint 2013站点,用Python脚本访问文档列表时,凭证验证正常,调用site.GetListCollection()也能返回包含目标文档库的数据:

from shareplum import Site
from shareplum.site import Version
from getpass import getpass as pwd
from requests_ntlm import HttpNtlmAuth

server_url = "https://sharepoint.company.net"
site_url = server_url + "/sites/<sitename>"
user_id = <user id>
pwd = pwd("Enter Password")

cred = HttpNtlmAuth(sid, pwd)
site = Site(site_url, auth=cred, version=Version.v2013)

但执行folder = site.Folder('Shared Documents')时触发JSONDecodeError,服务器返回XML格式的ContextWebInformation而非预期的JSON,错误详情如下:

---------------------------------------------------------------------------
JSONDecodeError                           Traceback (most recent call last)
File c:\jpy\lib\site-packages\requests\models.py:910, in Response.json(self, **kwargs)
    909 try:
--> 910     return complexjson.loads(self.text, **kwargs)
    911 except JSONDecodeError as e:
    912     # Catch JSON-related errors and raise as requests.JSONDecodeError
    913     # This aliases json.JSONDecodeError and simplejson.JSONDecodeError

File C:\ds\tools\python3.8\latest\lib\json\__init__.py:357, in loads(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    354 if (cls is None and object_hook is None and
    355         parse_int is None and parse_float is None and
    356         parse_constant is None and object_pairs_hook is None and not kw):
--> 357     return _default_decoder.decode(s)
    358 if cls is None:

File C:\ds\tools\python3.8\latest\lib\json\decoder.py:337, in JSONDecoder.decode(self, s, _w)
    333 """Return the Python representation of ``s`` (a ``str`` instance
    334 containing a JSON document).
    335 
    336 """
--> 337 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    338 end = _w(s, end).end()

File C:\ds\tools\python3.8\latest\lib\json\decoder.py:355, in JSONDecoder.raw_decode(self, s, idx)
    354 except StopIteration as err:
--> 355     raise JSONDecodeError("Expecting value", s, err.value) from None
    356 return obj, end

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

JSONDecodeError                           Traceback (most recent call last)
Input In [24], in <cell line: 1>()
----> 1 folder = site.Folder('Shared Documents')

File c:\jpy\lib\site-packages\shareplum\folder.py:12, in _Folder.__init__(self, session, folder_name, url)
      9 self.site_url = url
     10 self.timeout = 3
---> 12 self.info = self._create_folder()

File c:\jpy\lib\site-packages\shareplum\folder.py:30, in _Folder._create_folder(self)
     24 body = json.dumps(update_data)
     26 url = self.site_url + f"/_api/web/folders"
     28 headers = {'Accept': 'application/json;odata=verbose',
     29            'Content-Type': 'application/json;odata=verbose',
---> 30            'X-RequestDigest': self.contextinfo['FormDigestValue']}
     32 response = post(self._session, url=url, headers=headers, data=body, timeout=self.timeout)
     34 return response.json()

File c:\jpy\lib\site-packages\shareplum\folder.py:17, in _Folder.contextinfo(self)
     14 @property
     15 def contextinfo(self):
     16     response = post(self._session, self.site_url + "/_api/contextinfo")
---> 17     data = response.json()
     18     return data

File c:\jpy\lib\site-packages\requests\models.py:917, in Response.json(self, **kwargs)
    915     raise RequestsJSONDecodeError(e.message)
    916 else:
---> 917     raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)

JSONDecodeError: [Errno Expecting value] 
<?xml version="1.0" encoding="utf-8"?>
<d:GetContextWebInformation xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:type="SP.ContextWebInformation">
    <d:FormDigestTimeoutSeconds m:type="Edm.Int32">1800</d:FormDigestTimeoutSeconds>
    <d:FormDigestValue>0xuniqueid,20 Jul 2022 19:26:02 -0000</d:FormDigestValue>
    <d:LibraryVersion>15.0.5067.1000</d:LibraryVersion>
    <d:SiteFullUrl>https://sharepoint.company.net/sites/sitename</d:SiteFullUrl>
    <d:SupportedSchemaVersions m:type="Collection(Edm.String)">
        <d:element>14.0.0.0</d:element>
        <d:element>15.0.0.0</d:element>
    </d:SupportedSchemaVersions>
    <d:WebFullUrl>https://sharepoint.company.net/sites/sitename</d:WebFullUrl>
</d:GetContextWebInformation>: 0

问题原因与解决方案

错误核心是SharePoint 2013的/_api/contextinfo端点默认返回XML格式,但shareplum库的_Folder.contextinfo属性直接调用response.json()解析,导致格式不匹配。以下是三种可行解决方法:

方法1:修改请求头强制返回JSON

打开c:\jpy\lib\site-packages\shareplum\folder.py,找到contextinfo属性,修改为:

@property
def contextinfo(self):
    headers = {'Accept': 'application/json;odata=verbose'}
    response = post(self._session, self.site_url + "/_api/contextinfo", headers=headers)
    data = response.json()
    return data['d']

添加Accept头后,服务器会返回JSON格式的ContextWebInformation,可正常解析。

方法2:直接通过列表API访问文档库

既然site.GetListCollection()能正常返回数据,可绕过Folder方法,直接操作列表对象:

# 获取文档库列表对象
doc_lib = site.List('Shared Documents')
# 获取根文件夹下的文件
items = doc_lib.GetListItems()
# 精准获取文件夹详情
folder_items = doc_lib.GetListItems(query={'Where': ['Eq', 'FileDirRef', '/sites/<sitename>/Shared Documents']})

方法3:降级shareplum版本

部分新版本shareplum对SharePoint 2013兼容性不足,可降级到0.5.1版本:

pip install shareplum==0.5.1

旧版本的Folder方法针对SharePoint 2013做了适配,不会出现XML解析错误。

内容的提问来源于stack exchange,提问作者Mat Mellon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 11:06:19