python – 组合列表中的项目,直到找到包含特定文本的项目?

这很难解释.

我正在使用BeautifulSoup获取一些网页,我正在尝试将它们组织成一个列表.我只获取页面上具有“text”类的元素.像这样:

content = requests.get(url, verify=True)
soup = BeautifulSoup(content.text, 'lxml', parse_only=SoupStrainer('p'))
filtered_soup = soup.find_all("span", {"class":["text",
                                                "indent-1"]})
line_list = [line for line in filtered_soup]
#text_list = [line.get_text() for line in filtered_soup]

这很好用,但我也想结合列表中的一些项目.在网页上,一些class =“text …”的项目也有id =“en …”.他们在技术上应该是其他class =“text …”元素的父母,但网页还没有这样设置.

在我的“line_list”列表中,有一个同时具有class =“text …”和id =“en …”元素的项目,然后有一些项目只有class =“text …”,那么有一个项目同时具有class =“text …”和id =“en …”元素,并且这种模式不断重复.这是一种思考方式:

line_list = [A, a, a, a, B, b, b, C, c, c, c, c]

现在,这是难以解释的部分.假设line_list [0]有两个元素,line_list [1-3]只有“class”元素,而line_list [4]又有两个元素.我想迭代line_list并将项目组合成一个字符串.但是当迭代命中包含“id”和“class”的项目(即line_list [4])时,我希望它开始创建一个新的字符串.

或者,如果有人能想出更好的方法来做到这一点,那就太棒了.我打算尝试这样做:

line_string = ''.join(line_list)
split_list = line_string.split('id="en')

但是join命令抱怨line_string包含标签,而不是字符串.

我想知道用字典做这件事会更容易吗?例如,使具有“class”和“id”两个元素的元素以及仅具有“class”值的元素.它看起来像这样:

line_dic = {A: [a, a, a], B: [b, b], C: [c, c, c, c]}

这是html的示例,如果有人想玩它:

line_list = [<span class="text 1" id="en-13987>A<span class="small-caps" style="font-variant: small-caps">A</span>,
             <span class="indent-1"><span class="indent-1-breaks">    </span><span class="text 1">a</span></span>,
             <span class="text 1">a</span>,
             <span class="text 2" id="en-13988">B<span class="small-caps" style="font-variant: small-caps">B</span>B</span>,
             <span class="indent-1"><span class="indent-1-breaks">    </span><span class="text 2">b<span class="small-caps" style="font-variant: small-caps">b</span>b</span></span>,
             <span class="text 2">b<span class="small-caps" style="font-variant: small-caps">b</span>b</span>,
             <span class="text 3" id="en-13989">C</span>,
              <span class="indent-1"><span class="indent-1-breaks">    </span><span class="text 3">c<span class="small-caps" style="font variant: small-caps">c</span>c</span></span>,
             <span class="text 3">c<span class="small-caps" style="font-variant: small-caps">c</span>c</span>,]

很棒的想法,伙计们.万分感谢!

最佳答案 不是一个很酷的单行,但是,以下应该工作……:

text_list = []
current = []
for line in line_list:
    if line.get('id', '').startswith('en'):
        if current:
            text_list.append(' '.join(current))
            current = []
    current.append(line.text)
if current:
    text_list.append(' '.join(current))

例如,在示例测试开始后添加此代码

import bs4

content = '''
<span class='text' class='indent-1' id='en00'>And one</span>
<span class='text' class='indent-1'>And two</span>
<span class='text' class='indent-1'>And three</span>
<span class='text' class='indent-1' id='en01'>And four</span>
<span class='text' class='indent-1'>And five</span>
'''

soup = bs4.BeautifulSoup(content)
filtered_soup = soup.find_all("span", {"class":["text", "indent-1"]})
line_list = [line for line in filtered_soup]

test_list中的for x:将显示print(x)

And one And two And three
And four And five

这似乎符合预期的结果.

补充:这是一个可以说是更好的因素解决方案,但最终会变得更加冗长:

def has_id_en(elem):
    return elem.get('id', '').startswith('en')

def segment(sequence, is_head):
  current = []
  for x in sequence:
      if is_head(x):
          if current:
              yield current
              current = []
      current.append(x)
  if current:
      yield current

text_list = [' '.join(e.text for e in bunch)
             for bunch in segment(line_list, has_id_en)]

至少,通过这种方式,段逻辑可以重复用于类似的任务,其中序列中的项不需要是bs4对象,和/或确定项是否需要“追踪”子序列的方式与此特定问题不同.

点赞