【问题标题】:HTML and BeautifulSoup: how to iteratively parse when the structure is not always known beforehand?HTML 和 BeautifulSoup:当结构并不总是事先知道时如何迭代解析?
【发布时间】: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; 元素获取?

标签: python html json parsing beautifulsoup


【解决方案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())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多