Проблема с разбором html с помощью lxml с помощью xpath

Я пытаюсь проанализировать данные с интерактивного веб-сайта Google. Он отображается в JS, поэтому я использую Qt для загрузки сайта для анализа. Я считаю, что сайт загружен и отображается правильно, но по какой-то причине я получаю пустой список, возвращаемый мне, когда я выполняю код синтаксического анализа xpath.

Вот мой полный код:

import sys  
from PyQt4.QtGui import *  
from PyQt4.QtCore import *  
from PyQt4.QtWebKit import *  
from lxml import html 

class Render(QWebPage):  
  def __init__(self, url):  
    self.app = QApplication(sys.argv)  
    QWebPage.__init__(self)  
    self.loadFinished.connect(self._loadFinished)  
    self.mainFrame().load(QUrl(url))  
    self.app.exec_()  

  def _loadFinished(self, result):  
    self.frame = self.mainFrame()  
    self.app.quit() 

url = 'https://www.consumerbarometer.com/en/graph-builder/?question=M1&filter=country:singapore,canada,mexico,brazil,argentina,united_states,bulgaria,austria,belgium,croatia,czech_republic,denmark,estonia,finland,france,germany,greece,hungary,italy,ireland,latvia,lithuania,norway,netherlands,poland,portugal,russia,romania,serbia,slovakia,spain,slovenia,sweden,switzerland,ukraine,united_kingdom,australia,china,israel,hong_kong_sar,japan,korea,new_zealand,malaysia,taiwan,turkey,vietnam'  
#This does the magic.Loads everything
r = Render(url)  
#result is a QString.
result = r.frame.toHtml()

#QString should be converted to string before processed by lxml
formatted_result = str(result.toAscii())

#Next build lxml tree from formatted_result
tree = html.fromstring(formatted_result)

archive_links = tree.xpath('//*[@id="main-page-wrapper"]/div/section/div/section[1]/div/div/graph/div/div[4]/div/div/graph-bar-chart/div[2]/svg/g[1]/g[2]/g[1]/text()')
print archive_links

Это html, который я пытаюсь получить: <text class="bar-text-label" y="22" dy="10">Argentina</text>

Есть какие-нибудь мысли, почему мне возвращают []?


person metersk    schedule 04.02.2015    source источник


Ответы (1)


Вы можете сделать более короткое и надежное выражение xpath, и вы должны использовать пространства имен:

tree.xpath('//text[@class="bar-text-label"]/text()', namespaces={'n': 'http://www.w3.org/2000/svg'})

Альтернативным решением может быть использование пакета автоматизации браузера selenium:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


driver = webdriver.Firefox()
driver.get('https://www.consumerbarometer.com/en/graph-builder/?question=M1&filter=country:singapore,canada,mexico,brazil,argentina,united_states,bulgaria,austria,belgium,croatia,czech_republic,denmark,estonia,finland,france,germany,greece,hungary,italy,ireland,latvia,lithuania,norway,netherlands,poland,portugal,russia,romania,serbia,slovakia,spain,slovenia,sweden,switzerland,ukraine,united_kingdom,australia,china,israel,hong_kong_sar,japan,korea,new_zealand,malaysia,taiwan,turkey,vietnam')

// wait for svg to appear
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'svg')))

for text in driver.find_elements_by_class_name('bar-text-label'):
    print(text.text)

driver.close()
person alecxe    schedule 04.02.2015
comment
На самом деле я только что попробовал более короткое выражение xpath выше, и даже с добавлением пространства имен я все еще получаю пустой список. - person metersk; 04.02.2015
comment
@Meepl хм, я не пробовал использовать pyqt4, но я сохранил исходный код страницы в html-файле, проанализировал его с помощью lxml.html и использовал предоставленный xpath - у меня сработало. В любом случае, вас устроит альтернативное решение на основе селена? Спасибо. - person alecxe; 04.02.2015
comment
Да, конечно. у меня установлен селен, но я совершенно не знаком с ним - person metersk; 04.02.2015
comment
это сработало отлично! спасибо, теперь моя проблема в том, что я пытаюсь получить значение данных для каждой страны, которая имеет тип элемента: <rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="76" class="bar"></rect> можно ли получить атрибут data-value с помощью селена? Я пробовал for text in driver.find_elements_by_class_name('bar'): print(data_value.text), но это не сработало. - person metersk; 04.02.2015
comment
Я также пробовал это, но это не сработало: for data in driver.find_elements_by_xpath('//*[contains(@data-value)]/@data-value'): print(data.text) - person metersk; 04.02.2015
comment
@Meepl извините, AFK, насколько я понимаю, вы решили проблему? Спасибо. - person alecxe; 04.02.2015
comment
@alexce не волнуйся об этом! да, проблема решилась. Спасибо за вашу помощь!! - person metersk; 04.02.2015