我是 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。该列表需要按第三个跨度的内容排序,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)
这将对范围的内容进行排序,但不会对原始列表中的列表进行排序。我认为我需要更改 lambda 函数,但我目前不知所措。
我需要做什么或更改才能成功对列表进行排序,然后将这些更改保存在 HTML 文档中?
最佳答案
这实际上比您想象的要复杂一些,因此逐步完成它会有所帮助。
让我们从您的汤
开始:
>>> 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)
关于python - 如何使用 BeautifulSoup 4 按子元素对无序列表进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30158116/