无法使用请求解析网页的确切结果
Posted
技术标签:
【中文标题】无法使用请求解析网页的确切结果【英文标题】:Unable to parse an exact result from a webpage using requests 【发布时间】:2020-02-06 13:57:33 【问题描述】:我在 python 中创建了一个脚本来解析网页中的两个字段 - total revenue
,它与 date
有关。我追求的字段是 javascript 加密的。它们在 json 数组中的页面源中可用。以下脚本可以相应地解析这两个字段。
但是,问题在于该页面中可见的日期与页面源中可用的日期不同。
Webpage link
该网页中的日期类似于 this
页面源中的日期类似于 this
显然有一天的变化。
访问该webpage后,当您点击此标签Quarterly
时,您可以看到结果:
我试过了:
import re
import json
import requests
url = 'https://finance.yahoo.com/quote/GTX/financials?p=GTX'
res = requests.get(url)
data = re.findall(r'root.App.main[^]+(.*);',res.text)[0]
jsoncontent = json.loads(data)
container = jsoncontent['context']['dispatcher']['stores']['QuoteSummaryStore']['incomeStatementHistoryQuarterly']['incomeStatementHistory']
total_revenue = container[0]['totalRevenue']['raw']
concerning_date = container[0]['endDate']['fmt']
print(total_revenue,concerning_date)
我得到的结果(百万收入):
802000000 2019-06-30
我希望得到的结果:
802000000 2019-06-29
当我尝试使用此代码 AAPL
时,我得到了确切的日期,因此不能选择减去或添加一天。
我如何从该网站获得确切的日期?
顺便说一句,我知道如何使用 selenium 来获取它们,所以我只想坚持使用 requests
。
【问题讨论】:
如果日期最多相差一天,我的第一个猜测是差异来自时区转换。 我尝试使用不同的位置激活 *** 以查看结果,但变化仍然存在 @Janne Karila。 我刚试了你的代码,打印语句输出和页面上的一样(2019-6-30)。 是的,你是@Jack Fleeting,但其他代码肯定会有所不同。事实上,你可能会在其他时候得到不同的结果。在这一点上,Janne Karila 似乎在他的第一个猜测中是正确的。我想可能有什么办法可以解决这个问题。 能否再提供一些日期正确和日期错误的股票代码? 【参考方案1】:此答案的更新部分概述了日期差异的根本原因。
原始答案
JSON 中的一些原始值是 UNIX 时间戳。
修改后的代码参考:
concerning_date_fmt = container[0]['endDate']['fmt']
concerning_date_raw = container[0]['endDate']['raw']
print(f'concerning_date -- concerning_date_raw')
# output
2019-07-28 -- 1564272000
'endDate': 'fmt': '2019-07-28', 'raw': 1564272000
1564272000 是自 1970 年 1 月 1 日以来经过的秒数。该日期是 Unix 纪元的开始,时间采用协调世界时 (UTC)。 1564272000 相当于:07/28/2019 12:00am (UTC)。
您可以使用内置 Python 函数将这些时间戳转换为标准 datetime 格式
from datetime import datetime
unix_timestamp = int('1548547200')
converted_timestamp = datetime.utcfromtimestamp(unix_timestamp).strftime('%Y-%m-%dT%H:%M:%SZ')
print (converted_timestamp)
# output Coordinated Universal Time (or UTC)
2019-07-28T00:00:00Z
reformatted_timestamp = datetime.strptime(converted_timestamp, '%Y-%m-%dT%H:%M:%SZ').strftime('%d-%m-%Y')
print (reformatted_timestamp)
# output
28-07-2019
这仍然不能解决与 JSON 日期和列日期有时不同的原始问题。但这是我目前关于正在发生的日期差异的假设。
从 root.App.main 中提取的 json 日期(fmt 和 raw)采用协调世界时 (UTC)。这一点很清楚,因为 raw 中的 UNIX 时间戳。
表格列中显示的日期似乎位于东部标准时间 (EST) 时区。 EST 目前是 UTC-4。这意味着 2019-07-28 22:00 (10pm) EST 将是 2019-07-29 02:00 (2am) UTC。根据 traceroute,托管 finance.yahoo.com 的服务器看起来在美国 结果。这些值也在 json 文件中:
'exchangeTimezoneName': 'America/New_York' 'exchangeTimezoneShortName':'EDT'还有一些日期差异可能与网站使用的底层 React 代码相关联。这个问题更难诊断,因为代码不可见。
目前,我认为最好的解决方案是使用 UNIX 时间戳作为您的真实时间参考。此引用可用于替换表格列的日期。
在 JSON 文件和列之间肯定会发生某种类型的转换。
NVIDIA JSON 文件:'endDate': 'raw': 1561766400, 'fmt': '2019-06-29'
NVIDIA 相关总收入栏:2019 年 6 月 30 日
但总收入列日期应为 2019 年 6 月 28 日(美国东部时间),因为 1561766400 的 UNIX 时间戳是 2019 年 6 月 29 日凌晨 12:00(UTC)。
与 DELL 的差异大于基本 UNIX 时间戳和 EDT 时间戳转换。
戴尔 JSON 文件:"raw":1564704000,"fmt":"2019-08-02"
DELL 相关总收入列:2019 年 7 月 31 日
如果我们将 UNIX 时间戳转换为 EDT 时间戳,结果将是 2019 年 8 月 1 日,但在 DELL 示例中并非如此,即 2019 年 7 月 31 日。雅虎代码库中的某些东西一定会导致这种差异。
我开始相信 React 可能是造成这些日期差异的罪魁祸首,但如果不做更多研究,我无法确定。
如果 React 是根本原因,那么最好的选择是使用 JSON 数据中的日期元素。
2019 年 10 月 17 日更新答案
这个问题非常有趣,因为这些列日期似乎与公司的正式财政季度末相关联,而不是日期对话问题。
这里有几个例子
苹果公司 (AAPL) Atlassian Corporation Plc (TEAM) Arrowhead Pharmaceuticals, Inc. (ARWR):他们的专栏日期是:
2019 年 6 月 30 日 2019 年 3 月 31 日 12/31/2018 2018 年 9 月 30 日这些日期与这些财政季度相匹配。
第 1 季度(第一季度):1 月 1 日 - 3 月 31 日。 第 2 季度(第 2 季度):4 月 1 日 - 6 月 30 日。 第 3 季度(第 3 季度):7 月 1 日 - 9 月 30 日。 第 4 季度(第 4 季度):10 月 1 日 - 12 月 31 日正如这个 DELL 示例所示,这些财政季度结束日期可能会有很大差异。
戴尔(在纳斯达克发布) 财政季度末:2019 年 7 月
雅虎财经 专栏日期:7/31/2019
JSON 日期:2019-08-02
来自公司网站:
我们的财政年度是在最近的 1 月 31 日星期五结束的 52 或 53 周期间。我们的 2020 财政年度将在 2020 年 1 月 31 日结束。对于以前的财政年度,请参见下面的列表:我们的 2019 财政年度结束于2019 年 2 月 1 日 2018 财年于 2018 年 2 月 2 日结束 2017 财年于 2017 年 2 月 3 日结束 2016 财年于 2016 年 1 月 29 日结束 2015 财年于 2015 年 1 月 30 日结束2014 年 1 月 31 日 我们的 2013 财年于 2013 年 2 月 1 日结束Dell Technologies 的财政年度何时结束?
注意: 05-03-19 和 08-02-19 日期。
这些来自 DELL 的 JSON 季度数据:
'raw': 1564704000, 'fmt': '2019-08-02' 'raw': 1556841600, 'fmt': '2019-05-03'这些列日期似乎与公司的财政季度结束日期相关联。因此,我建议您使用 JSON 日期作为主要参考元素或相应的列日期。
附:雅虎出现了某种类型的日期巫术,因为他们似乎根据假期、周末和月末移动这些列季度日期。
【讨论】:
【参考方案2】:如 cmets 中所述,您需要将日期转换为适当的时区 (EST),这可以通过 datetime 和 dateutil
来完成。
这是一个工作示例:
import re
import json
import requests
from datetime import datetime, timezone
from dateutil import tz
url = 'https://finance.yahoo.com/quote/GTX/financials?p=GTX'
res = requests.get(url)
data = re.findall(r'root.App.main[^]+(.*);',res.text)[0]
jsoncontent = json.loads(data)
container = jsoncontent['context']['dispatcher']['stores']['QuoteSummaryStore']['incomeStatementHistoryQuarterly']['incomeStatementHistory']
total_revenue = container[0]['totalRevenue']['raw']
EST = tz.gettz('EST')
raw_date = datetime.fromtimestamp(container[0]['endDate']['raw'], tz=EST)
concerning_date = raw_date.date().strftime('%d-%m-%Y')
print(total_revenue, concerning_date)
【讨论】:
这似乎是我期望的结果。我不能像06-29-2019
而不是2019-06-29 19:00:00-05:00
那样格式化日期吗?谢谢。
@MITHU 我在更新中添加了这个。首先需要使用.date()
将datetime对象转换为日期,然后需要使用.strftime
将其转换为所需的格式。
如果我尝试使用这个代码 NVDA
会导致这个 link,我发现差异更大。
@MITHU 奇怪。这意味着 TZ 可能不是问题,因为NVIDIA
也在 EST 中。我会研究解决方案,但我现在不知道为什么会发生这种情况。【参考方案3】:
与其获取concerning_date
的fmt
,不如获取时间戳。
concerning_date = container[0]['endDate']['raw']
在上面的示例中,您将获得结果1561852800
,您可以将其转换为具有特定时区的日期。 (提示:使用datetime
和pytz
)。此时间戳将根据时区产生以下结果:
Date in Los Angeles*: 29/06/2019, 17:00:00
Date in Berlin* :30/06/2019, 02:00:00
Date in Beijing*: 30/06/2019, 07:00:00
Date in New York* :29/06/2019, 19:00:00
【讨论】:
以上是关于无法使用请求解析网页的确切结果的主要内容,如果未能解决你的问题,请参考以下文章