2016-04-21 9 views
0

Ich versuche, eine Abfrage an die RSCB PDB-Webdienste zu senden, wie beschrieben here.Anforderungen Bibliothek schlägt fehl, POST ordnungsgemäß, aber urllib erfolgreich [Python]

stelle ich die URL auf, und Abfrage als 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> 
""" 

ich dann definieren zwei Möglichkeiten, dieses Posting Daten:

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) 

Mit der ersten Funktion, gutes altmodisches urllib mit .request, bekomme ich das richtige Ergebnis - eine Liste von 4 Zeichenfolgen.

Mit der zweiten Funktion, die, soweit ich sagen kann, macht genau die gleiche Sache, bekomme ich eine JSP-Fehlermeldung HTML zurückgegeben. Dies ist die Fehlermeldung, wenn sie in einem Browser angezeigt:

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. 

ich ein wenig JSP weiß, aber ich haven nicht in der Lage gewesen, einen Grund für die POST Versagen von dieser Fehlermeldung aufzulesen, noch ist es mir klar, warum Anforderungen schlägt fehl, aber die Urlib der Standardbibliothek ist erfolgreich. Ich habe sogar versucht, den Quellcode der Requests-Bibliothek auf github durchzugehen, um genau herauszufinden, wie Requests Anfragen erstellen, aber bei diesem Unterfangen war ich nicht erfolgreich.

Diese Python ist 3. Ich traf zuerst dieses Problem mit Ubuntu und haben, da es unter Windows wiedergegeben 10.

Jede mögliche Hilfe würde sehr geschätzt werden.

Antwort

2

Ich habe es geschafft, das zu beheben.

Ich inspizierte die HTTP-Anfragen und sah gesendet werden, dass Anfragen dies sendete:

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> 

... und urllib dies sendete ...

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> 

Es gibt ein paar Header anders, und indem ich mit ihnen herumspielte, fand ich heraus, dass es der Content-Type-Header war, der für Anfragen benötigt wurde.

Im Folgenden nun funktioniert:

response = requests.post(
    url, 
    data=query_xml.encode(), 
    headers={'Content-Type': 'application/x-www-form-urlencoded'} 
) 

Dank Philipp für meinen Original-Code ausgeführt wird und sicherstellen, dass dies technisch möglich war. Ich vermute, er hat eine andere Version von Anfragen als ich.

+1

'application/x-www-form-urlencoded' ist der falsche Inhaltstyp, der dort gesendet werden soll. Die Tatsache, dass der Server es akzeptiert, ist bizarr. Sie * sollten * einen Inhaltstyp 'application/xml' oder' text/xml' senden. –

+0

Ich habe gerade beide ausprobiert und beide scheitern - es gibt keine Fehlermeldung zurück, die es nur an die RSCB-Dokumente für die Webdienste weiterleitet. Du hast Recht, und es ist ein wenig frustrierend, da sie es eines Tages ändern und alles kaputt machen könnten. –

+0

Obwohl bedenken Sie, dass ich technisch eher rohe Bytes als XML-Text sende, wie ich es zuerst kodiere. –

0

Auf meiner Ubuntu-Maschine funktioniert es gut.

#!/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") 

Beide drucken das gleiche aus. Welche genaue Version von Python benutzt du? Ich benutze Python 3.4.3 auf einem Ubuntu 14.03

+0

Das ist verrückt! Ich bin derzeit auf Windows, Python 3.5 ausgeführt. Meine Version der Anfragen ist 2.8.1. Ich installiere gerade WireShark, damit ich mir die HTTP-Anfrage ansehen kann, die tatsächlich meine Maschine verlässt und sehe, was der Unterschied ist. –

+0

Ich habe es gelöst! Siehe meine Antwort. –

Verwandte Themen