来自雅虎的python lxml etree小程序信息

Posted

技术标签:

【中文标题】来自雅虎的python lxml etree小程序信息【英文标题】:python lxml etree applet information from yahoo 【发布时间】:2016-12-24 17:41:06 【问题描述】:

雅虎财经更新了网站。我有一个用于提取分析师建议的 lxml/etree 脚本。然而,现在分析师的建议就在那里,但只是作为图形。您可以在 this page 上查看示例。右侧列名为“推荐趋势”的图表显示了分析师报告的数量,显示了强劲的买入、买入、持有、表现不佳和卖出。

我的猜测是雅虎将在接下来的一段时间内对页面进行一些调整,但这让我想知道这些数据是否可以以任何合理的方式提取?

    我的意思是,有没有办法让图形与它一起工作? 即使成功了,是否有合理的方法从图形中提取数据?

我以前是这样获取源码的:

url = 'https://finance.yahoo.com/quote/'+code+'/analyst?p='+code
tree = etree.html(urllib.request.urlopen(url).read())

然后在 html 树中查找数据。但显然现在不可能了。

【问题讨论】:

从记忆中,他们开始使用 react 所以很多内容现在是动态创建的,你是如何获得源代码的? 我将代码放在问题中。看起来内容肯定是动态创建的。我想我想知道是否可以提取此类内容。 是的,我刚刚看了一下,它是完全动态创建的,包括着色等。不过,您可以很容易地使用 selenium 获取值 我得查一下硒。从来没有听说过。感谢您的指点。它是 Python 的东西吗? 它的行为就像一个浏览器,即它可以运行 javascript,你可以将它与 Phantomjs 一起用于无头浏览。我用它做了一些工作,得到了所有的 x、y 轴刻度、值等。很容易,您实际上可以通过从标签中提取值来重新创建包括颜色代码的整个图表。现在完成它为时已晚,但如果我明天有空闲时间,我将添加完整的实现 【参考方案1】:

页面是非常动态的,并且涉及在浏览器中执行的大量 javascript。要遵循@Padraic 的关于切换到selenium 的建议,这里有一个完整的示例工作代码,它在最后生成一个月份趋势字典。每个条形的值按条形高度的比例计算:

from pprint import pprint

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

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://finance.yahoo.com/quote/CSX/analysts?p=CSX")

# wait for the chart to be visible
wait = WebDriverWait(driver, 10)
trends = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "section[data-reactid$=trends]")))
chart = trends.find_element_by_css_selector("svg.ratings-chart")

# get labels
month_names = [month.text for month in chart.find_elements_by_css_selector("g.x-axis g.tick")]
trend_names = [trend.text for trend in trends.find_elements_by_css_selector("table tr > td:nth-of-type(2)")]

# construct month-to-trend dictionary
data = 
months = chart.find_elements_by_css_selector("g[transform]:not([class])")
for month_name, month_data in zip(month_names, months):
    total = month_data.find_element_by_css_selector("text.total").text
    data[month_name] = 'total': total

    bars = month_data.find_elements_by_css_selector("g.bar rect")

    # let's calculate the values of bars as proportions of a bar height
    heights = trend_name: int(bar.get_attribute("height")) for trend_name, bar in zip(trend_names[::-1], bars)
    total_height = sum(heights.values())
    for trend_name, bar in zip(trend_names, bars):
        data[month_name][trend_name] = heights[trend_name] * 100 / total_height

driver.close()

pprint(data)

打印:

u'Aug': u'Buy': 19,
          u'Hold': 45,
          u'Sell': 3,
          u'Strong Buy': 22,
          u'Underperform': 8,
          'total': u'26',
 u'Jul': u'Buy': 18,
          u'Hold': 44,
          u'Sell': 3,
          u'Strong Buy': 25,
          u'Underperform': 7,
          'total': u'27',
 u'Jun': u'Buy': 21,
          u'Hold': 38,
          u'Sell': 3,
          u'Strong Buy': 28,
          u'Underperform': 7,
          'total': u'28',
 u'May': u'Buy': 21,
          u'Hold': 38,
          u'Sell': 3,
          u'Strong Buy': 28,
          u'Underperform': 7,
          'total': u'28'

total 值是您在每个条形顶部看到的标签。

希望这至少对您来说是一个好的开始。如果您希望我详细说明代码的任何部分或需要任何其他信息,请告诉我。

【讨论】:

【参考方案2】:

正如 cmets 所说,他们已经迁移到 ReactJS,所以 lxml 不再重要,因为 HTML 页面中没有数据。现在您需要环顾四周并找到他们从中提取数据的端点。如果是推荐趋势,它就在那里。

#!/usr/bin/env python3


import json
from pprint import pprint
from urllib.request import urlopen
from urllib.parse import urlencode


def parse():
    host   = 'https://query2.finance.yahoo.com'
    path   = '/v10/finance/quoteSummary/CSX'
    params = 
        'formatted' : 'true',
        'lang'      : 'en-US',
        'region'    : 'US',
        'modules'   : 'recommendationTrend'
    

    response = urlopen('?'.format(host, path, urlencode(params)))
    data = json.loads(response.read().decode())

    pprint(data)


if __name__ == '__main__':
    parse()

输出如下所示。


  'quoteSummary': 
    'error': None,
    'result': [
      'recommendationTrend': 
        'maxAge': 86400,
        'trend': [
            'buy': 0,
            'hold': 0,
            'period': '0w',
            'sell': 0,
            'strongBuy': 0,
            'strongSell': 0
          ,
          
            'buy': 0,
            'hold': 0,
            'period': '-1w',
            'sell': 0,
            'strongBuy': 0,
            'strongSell': 0
          ,
          
            'buy': 5,
            'hold': 12,
            'period': '0m',
            'sell': 2,
            'strongBuy': 6,
            'strongSell': 1
          ,
          
            'buy': 5,
            'hold': 12,
            'period': '-1m',
            'sell': 2,
            'strongBuy': 7,
            'strongSell': 1
          ,
          
            'buy': 6,
            'hold': 11,
            'period': '-2m',
            'sell': 2,
            'strongBuy': 8,
            'strongSell': 1
          ,
          
            'buy': 6,
            'hold': 11,
            'period': '-3m',
            'sell': 2,
            'strongBuy': 8,
            'strongSell': 1
          ]
        
    ]
  

如何查找数据

我所做的大致是:

    在目标小部件中找到一些独特的标记(比如图表值或趋势字符串) 页面的开源(对 HTML 和 JS 使用一些格式化程序,例如this) 在那里寻找令牌(在第三页中以/* -- Data -- */ 开头的部分) 搜索“.js”以获取脚本标签(或编程包含,例如 require.js)并在此处查找令牌 在 Firebug 或 Chromium 开发者工具中打开网络选项卡并检查 XHR 请求 然后使用Postman(如果您更喜欢终端,也可以使用 curl)去除额外的参数并查看终端的反应

【讨论】:

与拥有全功能浏览器和远程控制相比的绿色技术 ;-) 是的,我害怕有人发布直接的方法。绝对值得赏金! 这真的很好用。我想知道您如何确定要放入参数的正确内容?我只是模糊地理解它在做什么,所以我认为了解我将如何调整代码以适应其他信息(比如目标价格或其他)会很有用。 @DrXorile 我添加了一个部分。看看吧。 再次感谢。这太棒了。

以上是关于来自雅虎的python lxml etree小程序信息的主要内容,如果未能解决你的问题,请参考以下文章

python之lxml库etree

python之lxml库etree

Python3.7 lxml引入etree

python-docx-lxml.etree.XMLSyntaxError:AttValue长度太长

Python Xpath:lxml.etree.XPathEvalError:无效谓词

Python导入 from lxml import etree 导入不了