python - example - ¿Usando lxml para analizar HTML?
python lxml xpath (3)
Esto me está volviendo totalmente loco, he estado luchando con él durante muchas horas. Cualquier ayuda sería muy apreciada.
Estoy usando PyQuery 1.2.9 (que se construye sobre lxml
) para raspar esta URL . Solo quiero obtener una lista de todos los enlaces en la sección .linkoutlist
.
Esta es mi solicitud en su totalidad:
response = requests.get(''http://www.ncbi.nlm.nih.gov/pubmed/?term=The%20cost-effectiveness%20of%20mirtazapine%20versus%20paroxetine%20in%20treating%20people%20with%20depression%20in%20primary%20care'')
doc = pq(response.content)
links = doc(''#maincontent .linkoutlist a'')
print links
Pero eso devuelve una matriz vacía. Si utilizo esta consulta en su lugar:
links = doc(''#maincontent .linkoutlist'')
Entonces obtengo esto de vuelta este HTML:
<div xmlns="http://www.w3.org/1999/xhtml" xmlns:xi="http://www.w3.org/2001/XInclude" class="linkoutlist">
<h4>Full Text Sources</h4>
<ul>
<li><a title="Full text at publisher''s site" href="http://meta.wkhealth.com/pt/pt-core/template-journal/lwwgateway/media/landingpage.htm?issn=0268-1315&volume=19&issue=3&spage=125" ref="itool=Abstract&PrId=3159&uid=15107654&db=pubmed&log$=linkoutlink&nlmid=8609061" target="_blank">Lippincott Williams & Wilkins</a></li>
<li><a href="http://ovidsp.ovid.com/ovidweb.cgi?T=JS&PAGE=linkout&SEARCH=15107654.ui" ref="itool=Abstract&PrId=3682&uid=15107654&db=pubmed&log$=linkoutlink&nlmid=8609061" target="_blank">Ovid Technologies, Inc.</a></li>
</ul>
<h4>Other Literature Sources</h4>
...
</div>
Así que los selectores principales devuelven HTML con muchas etiquetas <a>
. Esto también parece ser HTML válido.
Más experimentación revela que lxml no le gusta el atributo xmlns
en el div de apertura, por alguna razón.
¿Cómo puedo ignorar esto en lxml y simplemente analizarlo como HTML normal?
ACTUALIZACIÓN : Intentando ns_clean
, sigue fallando:
parser = etree.XMLParser(ns_clean=True)
tree = etree.parse(StringIO(response.content), parser)
sel = CSSSelector(''#maincontent .rprt_all a'')
print sel(tree)
Buena suerte al conseguir que un análisis XML / DOM estándar funcione en la mayoría de HTML. Lo mejor sería usar BeautifulSoup ( pip install beautifulsoup4
o easy_install beautifulsoup4
), que tiene un montón de manejo para las estructuras construidas incorrectamente. Tal vez algo como esto en su lugar?
import requests
from bs4 import BeautifulSoup
response = requests.get(''http://www.ncbi.nlm.nih.gov/pubmed/?term=The%20cost-effectiveness%20of%20mirtazapine%20versus%20paroxetine%20in%20treating%20people%20with%20depression%20in%20primary%20care'')
bs = BeautifulSoup(response.content)
div = bs.find(''div'', class_=''linkoutlist'')
links = [ a[''href''] for a in div.find_all(''a'') ]
>>> links
[''http://meta.wkhealth.com/pt/pt-core/template-journal/lwwgateway/media/landingpage.htm?issn=0268-1315&volume=19&issue=3&spage=125'', ''http://ovidsp.ovid.com/ovidweb.cgi?T=JS&PAGE=linkout&SEARCH=15107654.ui'', ''https://www.researchgate.net/publication/e/pm/15107654?ln_t=p&ln_o=linkout'', ''http://www.diseaseinfosearch.org/result/2199'', ''http://www.nlm.nih.gov/medlineplus/antidepressants.html'', ''http://toxnet.nlm.nih.gov/cgi-bin/sis/search/r?dbs+hsdb:@term+@rn+24219-97-4'']
Sé que no es la biblioteca que querías usar, pero históricamente he golpeado mi cabeza contra las paredes en muchas ocasiones cuando se trata de DOM. Los creadores de BeautifulSoup han eludido muchos casos de borde que tienden a ocurrir en la naturaleza.
Necesitas manejar espacios de nombres , incluyendo uno vacío.
Solución de trabajo:
from pyquery import PyQuery as pq
import requests
response = requests.get(''http://www.ncbi.nlm.nih.gov/pubmed/?term=The%20cost-effectiveness%20of%20mirtazapine%20versus%20paroxetine%20in%20treating%20people%20with%20depression%20in%20primary%20care'')
namespaces = {''xi'': ''http://www.w3.org/2001/XInclude'', ''test'': ''http://www.w3.org/1999/xhtml''}
links = pq(''#maincontent .linkoutlist test|a'', response.content, namespaces=namespaces)
for link in links:
print link.attrib.get("title", "No title")
Imprime títulos de todos los enlaces que coinciden con el selector:
Full text at publisher''s site
No title
Free resource
Free resource
Free resource
Free resource
O simplemente configure el parser
en "html"
y olvídese de los espacios de nombres:
links = pq(''#maincontent .linkoutlist a'', response.content, parser="html")
for link in links:
print link.attrib.get("title", "No title")
Si recuerdo correctamente haber tenido un problema similar hace un tiempo. Puede "ignorar" el espacio de nombres asignándolo a None
esta manera:
sel = CSSSelector(''#maincontent .rprt_all a'', namespaces={None: "http://www.w3.org/1999/xhtml"})