2015-04-10 13 views
16

To doprowadza mnie do szału, zmagałem się z tym przez wiele godzin. Każda pomoc byłaby bardzo cenna.Używanie lxml do parsowania nazwanego HTML?

Używam PyQuery 1.2.9 (która jest zbudowana na bazie lxml) do skrobania this URL. Chcę tylko uzyskać listę wszystkich linków w sekcji .linkoutlist.

To jest mój wniosek w całości:

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 

Ale zwraca pustą tablicę. Jeśli używam tej kwerendy Zamiast:

links = doc('#maincontent .linkoutlist') 

Potem dostać to z powrotem to 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&amp;volume=19&amp;issue=3&amp;spage=125" ref="itool=Abstract&amp;PrId=3159&amp;uid=15107654&amp;db=pubmed&amp;log$=linkoutlink&amp;nlmid=8609061" target="_blank">Lippincott Williams &amp; Wilkins</a></li> 
     <li><a href="http://ovidsp.ovid.com/ovidweb.cgi?T=JS&amp;PAGE=linkout&amp;SEARCH=15107654.ui" ref="itool=Abstract&amp;PrId=3682&amp;uid=15107654&amp;db=pubmed&amp;log$=linkoutlink&amp;nlmid=8609061" target="_blank">Ovid Technologies, Inc.</a></li> 
    </ul> 
    <h4>Other Literature Sources</h4> 
    ... 
</div> 

Więc selektory rodziców zwracają HTML z dużą ilością <a> tagów. Wygląda to również na prawidłowy HTML.

Więcej eksperymentów ujawnia, że ​​lxml nie podoba się atrybutowi xmlns na początku elementu div, z jakiegoś powodu.

Jak mogę zignorować to w lxml i po prostu parsować jak zwykły HTML?

UPDATE: Próba ns_clean, nadal nie:

parser = etree.XMLParser(ns_clean=True) 
    tree = etree.parse(StringIO(response.content), parser) 
    sel = CSSSelector('#maincontent .rprt_all a') 
    print sel(tree) 

Odpowiedz

6

Potrzebujesz przestrzenie nazw uchwytów, w tym pusty.

Roztwór roboczy:

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") 

reprodukcje Tytuły wszystkich linków pasujących selektora:

Full text at publisher's site 
No title 
Free resource 
Free resource 
Free resource 
Free resource 

Lub po prostu ustawić parser do "html" i zapomnieć o przestrzeniach nazw:

links = pq('#maincontent .linkoutlist a', response.content, parser="html") 
for link in links: 
    print link.attrib.get("title", "No title") 
+0

T pasuje tak bardzo. Ciekawe, czy możesz mi powiedzieć, dlaczego widziałem ten obszar nazw dołączony do elementu div? Nie ma go w źródle strony. – Richard

+1

@Richard świetne pytanie, które sprawiło, że myślę, że przestrzenie nazw zostały wstawione przez pyquery, ponieważ próbowałem parsować zawartość z parserem xml, podczas gdy potrzebne było to zrobić przez parser html, zobacz aktualizację. Nadzieja, która pomaga. – alecxe

+0

@alexce aha! Dziękuję za wyjaśnienie. – Richard

0

Jeśli dobrze pamiętam z konieczności podobny problem sam jakiś czas temu. Można „ignoruj” przestrzeń nazw przez odwzorowanie go None tak:

sel = CSSSelector('#maincontent .rprt_all a', namespaces={None: "http://www.w3.org/1999/xhtml"}) 
2

Powodzenia uzyskanie standard XML/DOM analizowania pracować na większości HTML. Najlepszym rozwiązaniem byłoby użycie BeautifulSoup (pip install beautifulsoup4 lub easy_install beautifulsoup4), która ma wiele zastosowań w przypadku niepoprawnie zbudowanych struktur. Może zamiast tego coś takiego?

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:@[email protected]+24219-97-4'] 

wiem, że nie jest to biblioteka szukałeś w użyciu, ale historycznie uderzył głową w ściany przy wielu okazjach, jeśli chodzi o DOM. Twórcy BeautifulSoup omijali wiele skrajnych przypadków, które zdarzają się na wolności.

Powiązane problemy