【问题标题】:How do I sort an unordered list using BeautifulSoup 4 by a child element如何使用 BeautifulSoup 4 按子元素对无序列表进行排序
【发布时间】:2015-05-11 00:36:10
【问题描述】:

我是 Python 编码和 BeautifulSoup4 的新手。我有一个需要排序的 HTML 列表,它遵循以下模式:

<div id="mgioLangSelector">
<ul id="mgioLangList">
<li><a href="" class="mgio-autonym"><span class="mgioAutonymNative" lang="am">አማርኛ</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Amharic</span</a></li>
<li><a href="" class="mgio-autonym"><span class="mgioAutonymNative" lang="hr">hrvatski</span><span class="mgioAutonymSeperator"> / </span>        <span class="mgioAutonymEnglish">Croatian</span</a></li>
<li><a href="" class="mgio-autonym"><span class="mgioAutonymNative" lang="cs">čeština</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Czech</span</a></li>
<li><a href="" class="mgio-autonym"><span class="mgioAutonymNative" lang="vi">tiếng Việt</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Vietnamese</span</a></li>
<li><a href="" class="mgio-autonym"><span class="mgioAutonymNative" lang="sq">shqip</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Albanian</span</a></li>
</ul>
</div>

我需要对列表原位进行排序并保存生成的 HTML。列表需要按第三个span的内容排序,class= mgioAutonymEnglish

我怀疑我需要将sorted() 与适当的按键功能一起使用,但我会出现空白。

我已经尝试了以下代码:

from bs4 import BeautifulSoup
from lxml import etree
soup = BeautifulSoup(open("interimResults.html"), 'lxml', from_encoding="utf-8")
matches = soup.find_all("span", attrs={"class": "mgioAutonymEnglish"})
sorted(matches, key=lambda elem: elem.text)

这将对 span 的内容进行排序,但不会对原始列表中的列表进行排序。我假设我需要更改 lambda 函数,但我目前不知所措。

我需要做什么或更改才能成功对列表进行排序,然后将这些更改保存在 HTML 文档中?

【问题讨论】:

    标签: python sorting python-3.x beautifulsoup html-lists


    【解决方案1】:

    这实际上比您想象的要复杂一些,因此逐步完成会有所帮助。

    让我们从你的soup开始:

    >>> soup
    <html><body>
    ...
    <div id="mgioLangSelector">
    <ul id="mgioLangList">
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="am">አማርኛ</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Amharic</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="hr">hrvatski</span><span class="mgioAutonymSeperator"> / </span> <span class="mgioAutonymEnglish">Croatian</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="cs">čeština</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Czech</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="vi">tiếng Việt</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Vietnamese</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="sq">shqip</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Albanian</span></a></li>
    </ul>
    </div>
    ...
    </body></html>
    

    首先要做的是获取ul

    ul = soup.find(attrs={"id": "mgioLangList"})
    

    现在我们可以 extract() 从中提取所有 li 元素并将它们存储在一个列表中:

    items = [li.extract() for li in ul.find_all("li")]
    

    要对列表进行排序,我们需要一个键。你是在正确的路线上,但实际上它需要看起来像这样:

    items.sort(key=lambda e: e.find(attrs={"class": "mgioAutonymEnglish"}).string)
    

    现在我们有了li 元素的排序列表,我们可以将它们重新插入到文档中。可能不会立即明显的是,ul 不仅包含 li 元素——它们被换行符分隔,这些换行符仍然存在:

    >>> ul
    <ul id="mgioLangList">
    
    
    
    
    
    </ul>
    

    ...事实上,它们仍然是六个独立的'\n' 字符串:

    >>> ul.contents
    ['\n', '\n', '\n', '\n', '\n', '\n']
    

    为了在这些换行符之间插入我们的li元素的排序列表,我们可以使用内置的zip()函数和insert_after()方法:

    for linebreak, li in reversed(list(zip(ul.contents, items))):
        linebreak.insert_after(li)
    

    请注意,因为我们通过在迭代 ul.contents 时插入元素来修改它,所以有必要这样做 in reverse 以便 for 循环不会最终绊倒自己。

    所以……

    >>> soup
    <html><body>
    ...
    <div id="mgioLangSelector">
    <ul id="mgioLangList">
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="sq">shqip</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Albanian</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="am">አማርኛ</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Amharic</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="hr">hrvatski</span><span class="mgioAutonymSeperator"> / </span> <span class="mgioAutonymEnglish">Croatian</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="cs">čeština</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Czech</span></a></li>
    <li><a class="mgio-autonym" href=""><span class="mgioAutonymNative" lang="vi">tiếng Việt</span><span class="mgioAutonymSeperator"> / </span><span class="mgioAutonymEnglish">Vietnamese</span></a></li>
    </ul>
    </div>
    ...
    </body></html>
    

    这就是全部内容:

    ul = soup.find(attrs={"id": "mgioLangList"})
    items = [li.extract() for li in ul.find_all("li")]
    items.sort(key=lambda e: e.find(attrs={"class": "mgioAutonymEnglish"}).string)
    for linebreak, li in reversed(list(zip(ul.contents, items))):
        linebreak.insert_after(li)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 2016-01-26
      • 1970-01-01
      相关资源
      最近更新 更多