【问题标题】:Parsing HTML Python, BeautifulSoup解析 HTML Python,BeautifulSoup
【发布时间】:2014-03-06 21:36:51
【问题描述】:

我有几个包含以下类型信息的 html 文档:

<td class="principal-col">
<div class="pr-person">
<div class="name"><span id="pr_person-icon" class="bullet-male-left"></span><span class="person-link">Thomas A /Dumpling/</span></div>
<table class="events" border="0">
<tr>
<td class="factLabel">event1:&nbsp;</td>
<td>
4 February 1940          
<br/>
</td>
</tr> 
<tr>
<td class="factLabel">event2:&nbsp;</td>
<td>
9 October 2002   
<br/>Laplata, Md
</td>
</tr>

我正在尝试提取此人的姓名(此处:Thomas A Dumpling),以及 event1(此处:1940 年 2 月 4 日)和 event2 日期和地点(此处:2002 年 10 月 9 日,马里兰州拉普拉塔),从 html 文件中,并将内容放在 csv 文件“data.csv”的名为“Name”、“Event1”、“Event2”的列中。

如何从上面的 html 代码中提取名称到目前为止我还没有弄清楚。对于 event1 和 event2 日期信息,以下代码对于类似的 html 文件运行良好,但对于我在上面发布的 html 代码类型根本不起作用;也就是说,以下 Python 代码通过了,但它在 csv 文件的相应列中添加了“缺失”。

from bs4 import BeautifulSoup
import csv
import re
import glob
import os

f= csv.writer(open('data.csv', 'w'))
f.writerow(["Event1", "Event2"]) 

path = 'C:\\File-Path\\*'

for infile in glob.glob(os.path.join(path, "148929_S1N8-DQ7.htm")):
    soup = BeautifulSoup (open(infile))
    myDict = {}
    for item in ["event1:", "event2:"]:
        try:
            myDict[item] = soup.find('td', text=re.compile(r'^%s$' % item)).findNext('td').text
            myDict[item] = myDict[item].strip()
            myDict[item] = myDict[item].lstrip()
            myDict[item] = myDict[item].rstrip()
            myDict[item] = myDict[item].encode('UTF-8')
        except Exception:
            myDict[item] = "missing"
            pass
    f.writerow([myDict["event1:"], myDict["event2:"]])

任何指针都非常感谢!

【问题讨论】:

    标签: python html csv beautifulsoup


    【解决方案1】:

    首先,我将您的示例数据转换为有效的 html 页面并进行漂亮的打印。这样可以更轻松地查看正在发生的事情:

    <html><body><table><tr>
    <td class="principal-col">
      <div class="pr-person">
        <div class="name">
          <span id="pr_person-icon" class="bullet-male-left"></span>
          <span class="person-link">Thomas A /Dumpling/</span>
        </div>
        <table class="events" border="0">
          <tr>
            <td class="factLabel">event1:&nbsp;</td>
            <td>4 February 1940<br/></td>
          </tr> 
          <tr>
            <td class="factLabel">event2:&nbsp;</td>
            <td>9 October 2002<br/>Laplata, Md</td>
          </tr>
        </table>
      </div>
    </td>
    </tr></table></body></html>
    

    然后稍微切换一下你的程序:

    from bs4 import BeautifulSoup
    import csv
    import glob
    import os
    
    DATA_PATH = "c:\\file_path\\"
    FILESPEC  = "*.htm"
    OUTFILE   = "data.csv"
    
    def main():
        data = []
        for fname in glob.glob(os.path.join(DATA_PATH, FILESPEC)):
            with open(fname) as inf:
                pg = BeautifulSoup(inf.read())
                for person in pg.findAll('td', {'class':'principal-col'}):
                    data.append(get_data(person))
        data.sort()
    
        with open(os.path.join(DATA_PATH, OUTFILE), 'wb') as outf:
            outcsv = csv.writer(outf)
            outcsv.writerow(["Name", "Born", "Hired"])
            outcsv.writerows(data)
    
    if __name__ == "__main__":
        main()
    

    只留下实际的解析代码,

    def get_string(node, default=''):
        if node:
            return ', '.join(node.stripped_strings)
        else:
            return default
    
    def get_data(td_princ):
        name = get_string(td_princ.find('span', {'class':'person-link'})).replace('/', '')
    
        birth = hired = '(missing)'
        for event in td_princ.find('table', {'class': 'events'}).findAll('tr'):
            cnt = [get_string(cell) for cell in event.findAll('td')]
            if len(cnt) == 2:
                if cnt[0] == "event1:":
                    birth = cnt[1]
                elif cnt[0] == "event2:":
                    hired = cnt[1]
        return (name, birth, hired)
    

    当针对样本数据运行时,会生成一个看起来像这样的 csv 文件

    Name,Born,Hired
    Thomas A Dumpling,4 February 1940,"9 October 2002, Laplata, Md"
    

    【讨论】:

    • 谢谢休!如您所见,我对此真的很陌生...当我运行您的代码时,出现以下错误-您知道这可能是什么吗?非常感谢...“data.append(get_data(person)) NameError: global name 'get_data' is not defined”
    • 我想通了——这对我来说是一个非常愚蠢的错误。解析代码实际上需要先走。现在像魅力一样工作 - 再次感谢 Hugh!
    【解决方案2】:

    找到第一个标签的最简单方法是使用普通的findselect 也可以):

    soup.find(class_='person-link')
    Out[4]: <span class="person-link">Thomas A /Dumpling/</span>
    
    soup.select('.person-link')
    Out[5]: [<span class="person-link">Thomas A /Dumpling/</span>]
    

    注意findclass_ 的特殊用法,因为class 是python 中的保留字。

    'event1' 和 'event2' 使用select 更容易获取:

    soup.select('td .factLabel ~ td')
    Out[10]: 
    [<td>
    4 February 1940          
    <br/>
    </td>,
     <td>
    9 October 2002   
    <br/>Laplata, Md
    </td>]
    

    在上面的 css 选择器中,您要求 td 兄弟姐妹 td class="factLabel" 标记。

    如果上述任何语法令人困惑,请前往BeautifulSoup docs。他们有很多很好的例子。

    【讨论】:

      猜你喜欢
      • 2020-02-06
      • 2011-07-21
      • 2018-07-10
      • 2011-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多