我正在为msn钱创建刮板。我从站点获取了值,并通过几个循环将它们运行以按年份对它们进行排序。当我的for循环结束时,所有值都是2018数据集中的值。我的代码有什么问题?
from urllib.request import urlopen
from bs4 import BeautifulSoup
from lxml import etree
values = {}
values_by_year = {}
counter = 2013
dict_index = 0
temp = ''
url = "https://www.msn.com/en-us/money/stockdetails/financials/nas-googl/fi-a1u3rw?symbol=GOOGL&form=PRFIHQ"
tree = etree.HTML(urlopen(url).read())
for section in tree.xpath('//*[@id="table-content-area"]'):
for i in range(2, 32):
for x in section.xpath('./div/div/div[1]/div/ul[%s]/li[1]/p/text()'
% (i)):
if i == 6:
values[i] = 0
else:
values[x] = 0
for x in range(2015, 2019):
values_by_year[x] = values
for section in tree.xpath('//*[@id="table-content-area"]'):
for i in range(2, 32):
for y in range(1, 6):
for value in section.xpath(
'./div/div/div[1]/div/ul[%s]/li[%s]/p/text()' % (i,y)):
if y == 1:
temp = value
else:
print("value is ", counter+y, "y is ", y)
values_by_year[counter+y][temp] = value
print(values_by_year[2016])
print("\n------\n")
print(values_by_year[2017])
我没有收到任何错误消息。对于程序,我的预期结果是输出字典名称values_by_year,其中每年包含4个键。每年包含对应于年份的值的字典。例如,2015年的“期限结束日期”应为2015年12月31日,2016年的“结束日期”为2016年12月31日。
答案 0 :(得分:0)
我不确定您是否在执行此操作。不过,使用Beautifulsoup
可以执行此操作。
from bs4 import BeautifulSoup
import requests
import re
headers={'User-Agent':'Mozilla/5.0'}
data=requests.get('https://www.msn.com/en-us/money/stockdetails/financials/nas-googl/fi-a1u3rw?symbol=GOOGL&form=PRFIHQ',headers=headers).text
soup=BeautifulSoup(data,'html.parser')
dict_data={}
table=soup.select_one('div.table-rows')
cols=table.select('.column-heading .truncated-string')
for col in cols[1:]:
year=col.text
periodenddate=col.parent.find_next('div',class_='table-data-rows').find('p',title=re.compile(year)).text
dict_data[year]=periodenddate
print(dict_data)
{'2015': '12/31/2015', '2018': '12/31/2018', '2016': '12/31/2016', '2017': '12/31/2017'}
答案 1 :(得分:0)
这是使用字典和css类型的第n个伪类的方法。 BS4 4.7.1
row_dict
是一个字典,其字典中的所有键均从所有行列1的值(即Period End Date , Stmt Source
等)中拉出。
row_dict = dict.fromkeys([h.text.strip().replace('▶\n▼\n','') for h in table.select('.first-column')][1:])
它通过枚举进行循环,以利用计数器传递给类型的nth以选择与该键关联的适当行
for index, header in enumerate(row_dict, 2):
row = [item.text.strip() for item in table.select('[class^=level]:nth-of-type(' + str(index) + ') .financials-columns')]
例如,
row_dict['Period End Date']
将是
['12/31/2015', '12/31/2016', '12/31/2017', '12/31/2018']
我用每年的密钥生成顶级词典income_statement
:
income_statement = dict.fromkeys([h.text for h in table.select('.column-heading')][1:])
然后我循环搜索那些年份,生成与每个键关联的内部字典
for i,year in enumerate(income_statement):
income_statement[year] = dict()
然后,我通过向其添加row_dict的键(即所有列1的值)来填充每个内部dict。然后,我可以使用枚举通过键填充顶级词典内部年份词典的适当值
for k,v in row_dict.items():
income_statement[year][k] = row_dict[k][i]
Py
import requests
from bs4 import BeautifulSoup as bs
r = requests.get('https://www.msn.com/en-us/money/stockdetails/financials/nas-googl/fi-a1u3rw?symbol=GOOGL&form=PRFIHQ')
soup = bs(r.content, 'lxml')
table = soup.select_one('#financials-partial-view')
income_statement = dict.fromkeys([h.text for h in table.select('.column-heading')][1:])
row_dict = dict.fromkeys([h.text.strip().replace('▶\n▼\n','') for h in table.select('.first-column')][1:])
for index, header in enumerate(row_dict, 2):
row = [item.text.strip() for item in table.select('[class^=level]:nth-of-type(' + str(index) + ') .financials-columns')]
row_dict[header] = row
for i,year in enumerate(income_statement):
income_statement[year] = dict()
for k,v in row_dict.items():
income_statement[year][k] = row_dict[k][i]
print(income_statement)
收入表结构和内容示例:
答案 2 :(得分:0)
您的代码中的特定问题是这样的:
for x in range(2015, 2019):
values_by_year[x] = values
这会将键2015到2018设置为引用与dict
相同的values
,而不是副本。因此,当您这样做时:
values_by_year[counter+y][temp] = value
您不仅在修改与dict
关联的counter+y
,而且还修改了与 all 初始化键相关的那个。
最低限度的解决方法是更改:
for x in range(2015, 2019):
values_by_year[x] = values
收件人:
for x in range(2015, 2019):
values_by_year[x] = values.copy()
因此您可以按预期的方式初始化默认值,但是插入(浅)默认值dict
的副本(由于其中的值为int
,就足够了。)