HTML 和 BeautifulSoup:当结构并不总是事先知道时如何迭代解析?

Posted

技术标签:

【中文标题】HTML 和 BeautifulSoup:当结构并不总是事先知道时如何迭代解析?【英文标题】:HTML and BeautifulSoup: how to iteratively parse when the structure is not always known beforehand? 【发布时间】:2014-05-05 12:31:37 【问题描述】:

我从一个简单的 html 结构开始,如下所示:

感谢@alecxe 的帮助,我能够创建这个 JSON 字典:

u'Outer List': u'Inner List': [u'info 1', u'info 2', u'info 3']

使用他的代码:

from bs4 import BeautifulSoup

data = """your html goes here: see the very end of post""" 
soup = BeautifulSoup(data)

inner_ul = soup.find('ul', class_='innerUl')
inner_items = [li.text.strip() for li in inner_ul.ul.find_all('li')]

outer_ul_text = soup.ul.span.text.strip()
inner_ul_text = inner_ul.span.text.strip()

result = outer_ul_text: inner_ul_text: inner_items
print result

代码很棒,我一直在尝试以可迭代的方式重写它。

我的“真实”HTML 数据集更大更糟糕,我需要以一种可以处理这样的方式来扩展代码:

或者,也许数据看起来是这样的:

更糟糕的是,也许在sublist 之下,我们还有另一个sublist!最终,这是我的真实情况。

我的问题是:我找不到一种方法来概括上述 BeautifulSoup 代码来处理上述任何一种情况(更不用说第三种“更糟糕”的情况了!)。

当我事先无法访问 HTML 的确切结构时,如何递归/迭代地探查 HTML 的深度并提取信息? BeautifulSoup 甚至可以做到这一点吗?当然,我肯定缺少某种方法,先确定深度,然后再继续。

非常感谢您能做到这一点!

最后一个例子的 HTML 在这里:

<html>
 <body>
  <ul class="rootList">
   <li class="liItem endPlus">
    <span class="itemToBeAdded">
     Outer List
    </span>
   </li>
   <li class="noBulletsLi ">
    <ul class="innerUl">
     <li class="liItem crossPlus">
      <span class="itemToBeAdded">
       Inner List
      </span>
      <ul class="grayStarUl ">
       <li class="">
        <span class="phrasesToBeAdded">
         info 1
        </span>
       </li>
       <li class="">
        <span class="phrasesToBeAdded">
         info 2
         </span>
       </li>
       <li class="">
        <span class="phrasesToBeAdded">
         info 3
        </span>
             <ul class="grayStarUl">
                 <li class="">
                     <span class="phrasesToBeAdded">sublist</span>
                 </li>
             </ul>            
       </li>
      </ul>
     </li>
      </ul>
     </li>
    </ul>
 </body>
</html>

【问题讨论】:

见this。不过,我相信它在 Python 3.x 中。 谢谢!我已经尝试过了,恐怕它不能很好地解决我的特定问题。 (是的,它适用于 Python 3.x) 我不确定您要达到的目标。据我所知,您想从所有 中提取信息?事后保留结构重要还是数据本身就足够了? 只是一个问题,&lt;ul&gt; 描述是否总是从第一个 &lt;li&gt;&lt;span&gt; 元素获取? 【参考方案1】:

你可以编写两个递归调用对方的解析器:

def parse_list(tag):
    return map(parse_list_item, tag.find_all('li', recursive=False))

def parse_list_item(tag):
    text = tag.find(text=True, recursive=False).strip()
    text += '\n' + tag.span.text.strip() if tag.span.parent == tag else ''
    inner = tag.find('ul', recursive=False)
    if inner is None:  # no more nesting:
        return text.strip()
    else:  # more nesting
        return text.strip():parse_list(inner) if text else parse_list(inner)

上面没有使用任何class 信息,并且无论内部列表的深度如何,都应该可以工作:

>>> parse_list(soup.find('ul'))
[u'Outer List', [u'Inner List': [u'info 1', u'info 2', u'info 3': [u'sublist']]]]

【讨论】:

【参考方案2】:

我有点不确定您要达到的目标。所以我假设你想从所有跨度中提取数据而不关心结构。如果您更准确地解释您想要实现的目标,我会更新我的答案。

soup = BeautifulSoup(html_doc)
spans = soup.findall(class="phrasesToBeAdded")
text = []
for element in spans:
    text.append(element.get_text())

【讨论】:

以上是关于HTML 和 BeautifulSoup:当结构并不总是事先知道时如何迭代解析?的主要内容,如果未能解决你的问题,请参考以下文章

Beautifulsoup 上下文中 lxml 和 html5lib 的区别

爬虫基础篇-BeautifulSoup解析

使用 BeautifulSoup 从 HTML 创建 JSON 结构

BeautifulSoup学习 之结构

在 Python 中使用 BeautifulSoup 解析数据

使用python抓取并分析数据—链家网(requests+BeautifulSoup)(转)