请求库无法正确 POST 但 urllib 成功 [python]
requests library fails to POST properly but urllib succeeds [python]
我正在尝试 POST 查询 RSCB PDB Web 服务,如 here 所述。
我设置了 url,然后查询为 XML:
import urllib.request as urllib
import requests
url = "http://www.rcsb.org/pdb/rest/search"
queryText = """
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</description>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>
"""
然后我定义了两种 POSTing 数据的可能方式:
def query_old_fashioned(url, query_xml):
req = urllib.Request(url, data=query_xml.encode())
f = urllib.urlopen(req)
result = f.read()
return result.decode()
def query_with_requests(url, query_xml):
response = requests.post(url, data=query_xml.encode())
return response.text
# result = query_old_fashioned(url, queryText)
# result = query_with_requests(url, queryText)
使用第一个函数,使用老式的 urllib.request,我得到了正确的结果 - 4 个字符串的列表。
使用第二个函数,据我所知,它正在做 完全 相同的事情,我收到 JSP 错误消息 HTML 返回.这是在浏览器中显示的错误消息:
type Exception report
message
description The server encountered an internal error that prevented it from fulfilling this request.
exception
java.lang.NullPointerException
java.util.StringTokenizer.<init>(StringTokenizer.java:199)
java.util.StringTokenizer.<init>(StringTokenizer.java:221)
org.rcsb.servlet.RestfulServiceServlet.doPost(RestfulServiceServlet.java:1371)
javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:86)
org.pdb.util.web.OutOfServiceFilter.doFilter(OutOfServiceFilter.java:91)
org.pdb.util.web.DOSFilter.doFilter(DOSFilter.java:158)
org.pdb.util.web.AntiRobotFilter.doFilter(AntiRobotFilter.java:29)
org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:394)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.61 logs.
我知道一点 JSP,但我无法从这个错误消息中找到 POST 失败的原因,我也不清楚请求失败的原因但是标准库的 urllib 是成功的。我什至尝试在 github 上浏览请求库的源代码,试图准确地找到 requests 如何创建它的请求,但我没有成功。
这是使用 Python 3。我第一次遇到这个问题是使用 Ubuntu,然后在 Windows 10.
上重现了它
任何帮助将不胜感激。
在我的 Ubuntu 机器上运行良好。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import urllib.request as urllib
def query_old_fashioned(url, query_xml):
req = urllib.Request(url, data=query_xml.encode())
f = urllib.urlopen(req)
result = f.read()
return result.decode()
def query_with_requests(url, query_xml):
response = requests.post(url, data=query_xml.encode())
return response.text
def test():
url = "http://www.rcsb.org/pdb/rest/search"
query = """
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</description>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>"""
print(query_old_fashioned(url, query))
print(query_with_requests(url, query))
if __name__ == '__main__':
test()
print("done")
两者打印出来的一样。您使用的 python 的确切版本是什么?我在 Ubuntu 14.03
上使用 Python 3.4.3
我设法解决了这个问题。
我检查了正在发送的 HTTP 请求,发现请求正在发送这个:
POST /pdb/rest/search HTTP/1.1
Host: www.rcsb.org
User-Agent: python-requests/2.8.1
Connection: keep-alive
Accept: */*
Content-Length: 316
Accept-Encoding: gzip, deflate
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</de
scription>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>
...urllib 正在发送此...
POST /pdb/rest/search HTTP/1.1
Accept-Encoding: identity
Content-Type: application/x-www-form-urlencoded
Content-Length: 316
User-Agent: Python-urllib/3.4
Connection: close
Host: www.rcsb.org
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</de
scription>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>
有几个 header 不同,通过研究它们,我发现它是请求中需要的 Content-Type header。
以下现在有效:
response = requests.post(
url,
data=query_xml.encode(),
headers={'Content-Type': 'application/x-www-form-urlencoded'}
)
感谢 Philipp 运行 我的原始代码并验证这在技术上是可行的。我怀疑他的请求版本和我的不一样。
我正在尝试 POST 查询 RSCB PDB Web 服务,如 here 所述。
我设置了 url,然后查询为 XML:
import urllib.request as urllib
import requests
url = "http://www.rcsb.org/pdb/rest/search"
queryText = """
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</description>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>
"""
然后我定义了两种 POSTing 数据的可能方式:
def query_old_fashioned(url, query_xml):
req = urllib.Request(url, data=query_xml.encode())
f = urllib.urlopen(req)
result = f.read()
return result.decode()
def query_with_requests(url, query_xml):
response = requests.post(url, data=query_xml.encode())
return response.text
# result = query_old_fashioned(url, queryText)
# result = query_with_requests(url, queryText)
使用第一个函数,使用老式的 urllib.request,我得到了正确的结果 - 4 个字符串的列表。
使用第二个函数,据我所知,它正在做 完全 相同的事情,我收到 JSP 错误消息 HTML 返回.这是在浏览器中显示的错误消息:
type Exception report
message
description The server encountered an internal error that prevented it from fulfilling this request.
exception
java.lang.NullPointerException
java.util.StringTokenizer.<init>(StringTokenizer.java:199)
java.util.StringTokenizer.<init>(StringTokenizer.java:221)
org.rcsb.servlet.RestfulServiceServlet.doPost(RestfulServiceServlet.java:1371)
javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:86)
org.pdb.util.web.OutOfServiceFilter.doFilter(OutOfServiceFilter.java:91)
org.pdb.util.web.DOSFilter.doFilter(DOSFilter.java:158)
org.pdb.util.web.AntiRobotFilter.doFilter(AntiRobotFilter.java:29)
org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:394)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.61 logs.
我知道一点 JSP,但我无法从这个错误消息中找到 POST 失败的原因,我也不清楚请求失败的原因但是标准库的 urllib 是成功的。我什至尝试在 github 上浏览请求库的源代码,试图准确地找到 requests 如何创建它的请求,但我没有成功。
这是使用 Python 3。我第一次遇到这个问题是使用 Ubuntu,然后在 Windows 10.
上重现了它任何帮助将不胜感激。
在我的 Ubuntu 机器上运行良好。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import urllib.request as urllib
def query_old_fashioned(url, query_xml):
req = urllib.Request(url, data=query_xml.encode())
f = urllib.urlopen(req)
result = f.read()
return result.decode()
def query_with_requests(url, query_xml):
response = requests.post(url, data=query_xml.encode())
return response.text
def test():
url = "http://www.rcsb.org/pdb/rest/search"
query = """
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</description>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>"""
print(query_old_fashioned(url, query))
print(query_with_requests(url, query))
if __name__ == '__main__':
test()
print("done")
两者打印出来的一样。您使用的 python 的确切版本是什么?我在 Ubuntu 14.03
上使用 Python 3.4.3我设法解决了这个问题。
我检查了正在发送的 HTTP 请求,发现请求正在发送这个:
POST /pdb/rest/search HTTP/1.1
Host: www.rcsb.org
User-Agent: python-requests/2.8.1
Connection: keep-alive
Accept: */*
Content-Length: 316
Accept-Encoding: gzip, deflate
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</de
scription>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>
...urllib 正在发送此...
POST /pdb/rest/search HTTP/1.1
Accept-Encoding: identity
Content-Type: application/x-www-form-urlencoded
Content-Length: 316
User-Agent: Python-urllib/3.4
Connection: close
Host: www.rcsb.org
<?xml version="1.0" encoding="UTF-8"?>
<orgPdbQuery>
<version>B0907</version>
<queryType>org.pdb.query.simple.ExpTypeQuery</queryType>
<description>Experimental Method Search: Experimental Method=SOLID-STATE NMR</de
scription>
<mvStructure.expMethod.value>SOLID-STATE NMR</mvStructure.expMethod.value>
</orgPdbQuery>
有几个 header 不同,通过研究它们,我发现它是请求中需要的 Content-Type header。
以下现在有效:
response = requests.post(
url,
data=query_xml.encode(),
headers={'Content-Type': 'application/x-www-form-urlencoded'}
)
感谢 Philipp 运行 我的原始代码并验证这在技术上是可行的。我怀疑他的请求版本和我的不一样。