python - 请求库无法正确发布,但 urllib 成功 [python]

标签 python http post python-requests urllib

我正在尝试向 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>
"""

然后我定义了两种可能的 POST 数据方式:

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 上重现了它。

非常感谢任何帮助。

最佳答案

我设法解决了这个问题。

我检查了正在发送的 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用于运行我的原始代码并验证这在技术上是可行的。我怀疑他的请求版本与我不同。

关于python - 请求库无法正确发布,但 urllib 成功 [python],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36767595/

相关文章:

python - ubuntu: 'geckodriver' 可执行文件需要在 PATH 中

python - TensorFlow - 当损失达到定义值时停止训练

javascript - 从 NodeJS 内部调用 Express Route

Python远程追加文件

python - Django 和查询字符串参数

使用 %s 的 Python MySQL Connector 数据库查询失败

java - 读取 HttpPost 响应

java - Spring MVC Controller : what is the difference between "return forward", "return redirect"和 "return jsp file"

objective-c - Objective-C 中的简单 http post 示例?

javascript - 来自 promise 的 Angular $http.post 值