【问题标题】:Extracting data from HTML with Python使用 Python 从 HTML 中提取数据
【发布时间】:2013-06-12 04:15:06
【问题描述】:

我的代码在 Python 中处理了以下文本:

<td>
<a href="http://www.linktosomewhere.net" title="title here">some link</a>
<br />
some data 1<br />
some data 2<br />
some data 3</td>

您能建议我如何从&lt;td&gt; 中提取数据吗? 我的想法是把它放在一个 CSV 文件中,格式如下:some link, some data 1, some data 2, some data 3

我希望没有正则表达式可能会很困难,但实际上我仍然在与正则表达式作斗争。

我或多或少地以以下方式使用了我的代码:

tabulka = subpage.find("table")

for row in tabulka.findAll('tr'):
    col = row.findAll('td')
print col[0]

理想情况下是让每个 td 在某个数组中竞争。上面的html是python的结果。

【问题讨论】:

  • 您可以使用 Beautifoulsoup crummy.com/software/BeautifulSoup/bs3/documentation.html 来提取信息,而不是使用正则表达式。
  • 不要使用正则表达式来解析非平凡的 HTML。
  • 我可以使用 BeautifulSoup 从 td 中提取数据,但是接下来如何处理里面的数据呢?

标签: python html


【解决方案1】:

我从未使用过 BeautifulSoup,但我敢打赌它是“html-tag-aware”并且可以处理“filler”空间。但是由于 html 标记文件是结构化的(并且通常由网页设计程序生成),您也可以尝试使用 Python 的 .split() 方法的直接方法。顺便说一句,我最近使用这种方法来解析一个真实世界的 url/html 来做一些与 OP 想要的非常相似的事情。

虽然 OP 只想从 &lt;a&gt; 标记中提取一个字段,但下面我们会提取“通常的两个”字段。

代码:

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Extracting data from HTML using split()
# Link: https://stackoverflow.com/questions/17126686/extracting-data-from-html-with-python
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys

page     = """blah blah blah
<td>
<a href="http://www.link1tosomewhere.net" title="title1 here">some link1</a>
<br />
some data1 1<br />
some data1 2<br />
some data1 3</td>
mlah mlah mlah
<td>
<a href="http://www.link2tosomewhere.net" title="title2 here">some link2</a>
<br />
some data2 1<br />
some data2 2<br />
some data2 3</td>
flah flah flah
"""

#--------*---------*---------*---------*---------*---------*---------*---------#
while 1:#                          M A I N L I N E                             #
#--------*---------*---------*---------*---------*---------*---------*---------#
    page = page.replace('\n','')   # remove \n from test html page
    csv = ''
    li = page.split('<td><a ')
    for i in range(0, len(li)):
        if li[i][0:6] == 'href="':
            s = li[i].split('</td>')[0]
#                                  # li2 ready for csv            
            li2 = s.split('<br />')
#                                  # create csv file
            for j in range(0, len(li2)):
#                                  # get two fields from li2[0]               
                if j == 0:
                    li3 = li2[0].split('"')
                    csv = csv + li3[1] + ','
                    li4 = li3[4].split('<')
                    csv = csv + li4[0][1:] + ','
#                                  # no comma on last field - \n instead
                elif j == len(li2) - 1:
                    csv = csv + li2[j] + '\n'
#                                  # just write out middle stuff                    
                else:
                    csv = csv + li2[j] + ','
    print(csv)                    
    sys.exit()

输出:

>>> 
= RESTART: C:\Users\Mike\AppData\Local\Programs\Python\Python36-32\board.py =
http://www.link1tosomewhere.net,some link1,some data1 1,some data1 2,some data1 3
http://www.link2tosomewhere.net,some link2,some data2 1,some data2 2,some data2 3

>>> 

【讨论】:

    【解决方案2】:

    您不应该在 html 上使用正则表达式。您应该使用 BeautifulSoup 或 lxml。下面是一些使用 BeautifulSoup 的示例:

    你的 td 标签实际上是这样的:

    <td>newline
    <a>some link</a>newline
    <br />newline
    some data 1<br />newline
    some data 2<br />newline
    some data 3</td>
    

    所以 td.text 看起来像这样:

    <newline>some link<newline><newline>some data 1<newline>some data 2<newline>some data 3
    

    您可以看到每个字符串至少由一个换行符分隔,这样您就可以将每个字符串分开。

    from bs4 import BeautifulSoup as bs
    import re
    
    html = """<td>
    <a href="http://www.linktosomewhere.net" title="title here">some link</a>
    <br />
    some data 1<br />
    some data 2<br />
    some data 3</td>"""
    
    soup = bs(html)
    tds = soup.find_all('td')
    csv_data = []
    
    for td in tds:
        inner_text = td.text
        strings = inner_text.split("\n")
    
        csv_data.extend([string for string in strings if string])
    
    print(",".join(csv_data))
    
    --output:--
    some link,some data 1,some data 2,some data 3
    

    或者更简洁:

    for td in tds:
        print(re.sub("\n+", ",", td.text.lstrip() ) ) 
    
    --output:--
    some link,some data 1,some data 2,some data 3
    

    但该解决方案很脆弱,因为如果您的 html 如下所示,它将无法工作:

    <td>
    <a href="http://www.linktosomewhere.net" title="title here">some link</a>
    <br />some data 1<br />some data 2<br />some data 3</td>
    

    现在 td.text 看起来像这样:

    <newline>some link<newline>some data 1some data2some data3
    

    并且没有办法确定某些字符串的开始和结束位置。但这只是意味着你不能使用 td.text——还有其他方法可以识别每个字符串:

    1)

    from bs4 import BeautifulSoup as bs
    import re
    
    html = """<td>
    <a href="http://www.linktosomewhere.net" title="title here">some link</a>
    <br />some data 1<br />some data 2<br />some data 3</td>"""
    
    soup = bs(html)
    tds = soup.find_all('td')
    csv_data = []
    
    for td in tds:
        a_tags = td.find_all('a')
    
        for a_tag in a_tags:
            csv_data.append(a_tag.text)
            br_tags = a_tag.findNextSiblings('br')
    
            for br in br_tags:
                csv_data.append(br.next.strip())  #get the element after the <br> tag
    
    csv_str = ",".join(csv_data)
    print(csv_str)
    
    --output:--
    some link,some data 1,some data 2,some data 3
    

    2)

    for td in tds:
        a_tag = td.find('a')
        if a_tag: csv_data.append(a_tag.text)
    
        for string in a_tag.findNextSiblings(text=True):  #find only text nodes
            string = string.strip()
            if string: csv_data.append(string)
    
    csv_str = ",".join(csv_data)
    print(csv_str)
    
    --output:--
    some link,some data 1,some data 2,some data 3
    

    3)

    for td in tds:
        a_tag = td.find('a')
        if a_tag: csv_data.append(a_tag.text)
    
        text_strings = a_tag.findNextSiblings( text=re.compile('\S+') )  #find only non-whitespace text nodes
        csv_data.extend(text_strings)
    
    csv_str = ",".join(csv_data)
    print(csv_str)
    
    --output:--
    some link,some data 1,some data 2,some data 3
    

    【讨论】:

      【解决方案3】:

      获取BeautifulSoup 并使用它。太好了。

      $> easy_install pip
      $> pip install BeautifulSoup
      $> python
      >>> from BeautifulSoup import BeautifulSoup as BS
      >>> import urllib2
      >>> html = urllib2.urlopen(your_site_here)
      >>> soup = BS(html)
      >>> elem = soup.findAll('a', {'title': 'title here'})
      >>> elem[0].text
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-01
      • 2021-10-22
      • 2020-10-17
      相关资源
      最近更新 更多