这很难解释.
我正在使用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对象,和/或确定项是否需要“追踪”子序列的方式与此特定问题不同.