【问题标题】:How to find the nearest above sibling <li> for each <li class=""><a>?如何为每个 <li class=""><a> 找到上面最近的兄弟 <li>?
【发布时间】:2021-08-08 05:11:29
【问题描述】:

我的示例 html 是

<li><h4>A0: Pronouns</h4></li>
<li class="">
    <a>bb</a>
    <a>cc</a>
</li>
<li class="">
    <a>dd</a>
    <a>ee</a>
</li>
<li><h4>A0: Verbs Tenses & Conjugation</h4></li>
<li class="">
    <a>ff</a>
    <a>gg</a>
</li>
<li class="">
    <a>hh</a>
    <a>kk</a>
</li>
<li class="">
    <a>jj</a>
    <a>ii</a>
</li>

对于每个元素&lt;li class=""&gt;&lt;a&gt;,我想找到它最接近的上面兄弟&lt;li&gt;&lt;h4&gt;。例如,

  • &lt;li class=""&gt;&lt;a&gt;bb&lt;/a&gt;&lt;/li&gt; 对应于&lt;li&gt;&lt;h4&gt;A0: Pronouns&lt;/h4&gt;&lt;/li&gt;

  • &lt;li class=""&gt;&lt;a&gt;dd&lt;/a&gt;&lt;/li&gt; 对应于&lt;li&gt;&lt;h4&gt;A0: Pronouns&lt;/h4&gt;&lt;/li&gt;

  • &lt;li class=""&gt;ff&lt;a&gt;dd&lt;/a&gt;&lt;/li&gt; 对应于&lt;li&gt;&lt;h4&gt;A0: Verbs Tenses &amp; Conjugation&lt;/h4&gt;&lt;/li&gt;

  • &lt;li class=""&gt;hh&lt;a&gt;dd&lt;/a&gt;&lt;/li&gt; 对应于&lt;li&gt;&lt;h4&gt;A0: Verbs Tenses &amp; Conjugation&lt;/h4&gt;&lt;/li&gt;

  • &lt;li class=""&gt;jj&lt;a&gt;dd&lt;/a&gt;&lt;/li&gt; 对应于&lt;li&gt;&lt;h4&gt;A0: Verbs Tenses &amp; Conjugation&lt;/h4&gt;&lt;/li&gt;

能否请您详细说明如何操作?

import requests
from bs4 import BeautifulSoup

session = requests.Session()
headers = {
    'Accept-Encoding': 'gzip, deflate, sdch',
    'Accept-Language': 'en-US,en;q=0.8',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
}

link = 'https://french.kwiziq.com/revision/grammar'
r = session.get(link, headers = headers)
soup = BeautifulSoup(r.content, 'html.parser')

for d in soup.select('.callout-body > ul li > a:nth-of-type(1)'):
    print(d)

【问题讨论】:

  • 您到底有什么问题?访问元素的previous_sibling?找出其中哪一个是li,并以h4 作为其第一个孩子?

标签: python beautifulsoup css-selectors


【解决方案1】:

你可以使用.find_previous('h4'):

import requests
from bs4 import BeautifulSoup


url = "https://french.kwiziq.com/revision/grammar"

soup = BeautifulSoup(requests.get(url).content, "html.parser")
for a in soup.select(".callout  li > a:nth-of-type(1)"):
    print(
        "{:<70} {}".format(
            a.get_text(strip=True), a.find_previous("h4").get_text(strip=True)
        )
    )

打印:

Saying your name: Je m'appelle, Tu t'appelles, Vous vous appelez       A0: Pronouns
Tu and vous are used for three types of you                            A0: Pronouns
Je becomes j' with verbs beginning with a vowel (elision)              A0: Verbs Tenses & Conjugation
J'habite à [city] = I live in [city]                                   A0: Idioms, Idiomatic Usage, and Structures
Je viens de + [city] = I'm from + [city]                               A0: Idioms, Idiomatic Usage, and Structures
Conjugate être (je suis, tu es, vous êtes) in Le Présent (present tense) A0: Verbs Tenses & Conjugation
Make most adjectives feminine by adding -e                             A0: Adjectives & Adverbs
Nationalities differ depending on whether you're a man or a woman (adjectives) A0: Adjectives & Adverbs
Conjugate avoir (j'ai, tu as, vous avez) in Le Présent (present tense) A0: Verbs Tenses & Conjugation
Using un, une to say "a" (indefinite articles)                         A0: Nouns & Articles

...

French vocabulary and grammar lists by theme                           C1: Idioms, Idiomatic Usage, and Structures
French Fill-in-the-Blanks Tests                                        C1: Idioms, Idiomatic Usage, and Structures

【讨论】:

  • 除了优雅的代码(一如既往 ^^),我非常感谢您在格式化如此漂亮的输出方面的奉献。
【解决方案2】:

您可以在 CSS 路径中使用 :is

from bs4 import BeautifulSoup as soup
from collections import defaultdict
d, l = defaultdict(list), None
for i in soup1.select('li > :is(a, h4):nth-of-type(1)'):
   if i.name == 'h4':
      l = i.get_text(strip=True)
   else:
      d[l].append(i.get_text(strip=True))

print(dict(d))

输出:

{'A0: Pronouns': ['bb', 'dd'], 'A0: Verbs Tenses & Conjugation': ['ff', 'hh', 'jj']}

输出存储与语法部分关联的每个li 的第一个a。如果您只想将1-1 部分用于组件结果,则可以使用字典理解:

new_d = {a:b for a, (b, *_) in d.items()}

输出:

{'A0: Pronouns': 'bb', 'A0: Verbs Tenses & Conjugation': 'ff'}

【讨论】:

  • 你的紧凑输出(一个字典)很有趣。实际上,我只想要每个&lt;li class=""&gt;第一个 &lt;a&gt;。这就是我使用a:nth-of-type(1) 的原因。你能修改你的代码来实现这个吗?
  • 非常感谢您的详细更新:v
猜你喜欢
  • 2013-12-12
  • 2013-11-12
  • 2011-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多