将HTML数据解析成Python列表以进行操作

4
我想读取 HTML 网站并提取数据,例如,我想读取公司过去 5 年的每股收益(EPS)。基本上,我可以读取它并可以使用 BeautifulSoup 或 html2text 创建一个大文本块。然后,我想搜索文件,我一直在使用 re.search,但似乎无法正常工作。这是我要访问的行:
EPS(基本)\ n13.4620.6226.6930.1732.81\n\n
所以我想创建一个名为 EPS 的列表:[13.46, 20.62, 26.69, 30.17, 32.81]。
谢谢任何帮助。
from stripogram import html2text
from urllib import urlopen
import re
from BeautifulSoup import BeautifulSoup

ticker_symbol = 'goog'
url = 'http://www.marketwatch.com/investing/stock/'
full_url = url + ticker_symbol + '/financials'  #build url

text_soup = BeautifulSoup(urlopen(full_url).read()) #read in 

text_parts = text_soup.findAll(text=True)
text = ''.join(text_parts)

eps = re.search("EPS\s+(\d+)", text)
if eps is not None:
    print eps.group(1)

soup.prettify()后的HTML代码如下:</a> EPS (基本) </td> <td class="valueCell"> 13.46 </td> <td class="valueCell"> 20.62 </td> <td class="valueCell"> 26.69 </td> <td class="valueCell"> 30.17 </td> <td class="valueCell"> 32.81 </td> - Warren Lamont
3个回答

2

使用正则表达式解析HTML并不是一种好的实践。建议使用BeautifulSoup解析器:查找具有rowTitle类和其中包含EPS (Basic)文本的单元格,然后迭代下一个具有valueCell类的兄弟节点:

from urllib import urlopen
from BeautifulSoup import BeautifulSoup

url = 'http://www.marketwatch.com/investing/stock/goog/financials'
text_soup = BeautifulSoup(urlopen(url).read()) #read in

titles = text_soup.findAll('td', {'class': 'rowTitle'})
for title in titles:
    if 'EPS (Basic)' in title.text:
        print [td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text]

打印:

['13.46', '20.62', '26.69', '30.17', '32.81']

希望这有所帮助。

这是一个非常好的和简单的解决方案。但是当我运行它时,输出中会多出一个额外的u字符:[u'13.46',u'20.62',u'26.69',u'30.17',u'32.81'] 有什么想法吗? - Warren Lamont

2
我会采取一种非常不同的方法。我们使用LXML来爬取HTML页面。
我们转换的原因之一是因为BS有一段时间没有得到维护 - 或者我应该说没有更新。
在我的测试中,我运行了以下内容。
import requests
from lxml import html
from collections import OrderedDict
page_as_string = requests.get('http://www.marketwatch.com/investing/stock/goog/financials').content

tree = html.fromstring(page_as_string)

现在我看了一下这个页面,发现数据被分成了两个表格。由于你想要EPS的数据,我注意到它在第二个表格中。我们可以编写一些代码来自动排序,但我会把这个留给你自己去做。
tables = [ e for e in tree.iter() if e.tag == 'table']
eps_table = tables[-1]

现在我注意到第一行有列标题,因此我想将所有行分开。
table_rows = [ e for e in eps_table.iter() if e.tag == 'tr']

现在让我们获取列标题:
column_headings =[ e.text_content() for e in table_rows[0].iter() if e.tag == 'th']

最后,我们可以将列标题映射到行标签和单元格值。
my_results = []
for row in table_rows[1:]:
    cell_content = [ e.text_content() for e in row.iter() if e.tag == 'td']
    temp_dict = OrderedDict()
    for numb, cell in enumerate(cell_content):
        if numb == 0:
            temp_dict['row_label'] = cell.strip()
         else:
            dict_key = column_headings[numb]
            temp_dict[dict_key] = cell

    my_results.append(temp_dict)

现在访问结果。
for row_dict in my_results:
    if row_dict['row_label'] == 'EPS (Basic)':
        for key in row_dict:
            print key, ':', row_dict[key]   


row_label :  EPS (Basic)
2008 : 13.46
2009 : 20.62
2010 : 26.69
2011 : 30.17
2012 : 32.81
5-year trend : 

现在还有更多的工作要做,例如我没有测试正方形(每行单元格数相等)。
最后,我是一个新手,我怀疑其他人会建议更直接的方法来获取这些元素(如xPath或cssselect),但这确实有效,并以良好的结构方式获取表中的所有内容。
我应该补充说,表中的每一行都可用,它们按原始行顺序排列。 my_results列表中的第一项(一个字典)具有来自第一行的数据,第二项具有来自第二行的数据,依此类推。
当我需要新版本的lxml时,我访问由UC-IRVINE维护的页面。
我希望这可以帮助你。

1
from bs4 import BeautifulSoup
import urllib2
import lxml
import pandas as pd

url = 'http://markets.ft.com/research/Markets/Tearsheets/Financials?s=CLLN:LSE&subview=BalanceSheet'

soup = BeautifulSoup(urllib2.urlopen(url).read())

table = soup.find('table', {'data-ajax-content' : 'true'})

data = []

for row in table.findAll('tr'):
    cells = row.findAll('td')
    cols = [ele.text.strip() for ele in cells]
    data.append([ele for ele in cols if ele])

df = pd.DataFrame(data)

print df

dictframe = df.to_dict()

print dictframe

上面的代码将从网页中获取一个DataFrame,然后使用它创建一个Python字典。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接