这是html
<table>
<tr>
<td class="break">mono</td>
</tr>
<tr>
<td>c1</td>
<td>c2</td>
<td>c3</td>
</tr>
<tr>
<td>c11</td>
<td>c22</td>
<td>c33</td>
</tr>
<tr>
<td class="break">dono</td>
</tr>
<tr>
<td>d1</td>
<td>d2</td>
<td>d3</td>
</tr>
<tr>
<td>d11</td>
<td>d22</td>
<td>d33</td>
</tr>
</table>
现在我想在csv文件中输出如下:
^{pr2}$但我得到的输出是这样的:
mono
c1 c2 c3
c11 c22 c33
dono
d1 d2 d3
d11 d22 d33
这是我的代码:
import codecs
from bs4 import BeautifulSoup
with codecs.open('dump.csv', "w", encoding="utf-8") as csvfile:
f = open("input.html","r")
soup = BeautifulSoup(f)
t = soup.findAll('table')
for table in t:
rows = table.findAll('tr')
for tr in rows:
cols = tr.findAll('td')
for td in cols:
csvfile.write(str(td.find(text=True)))
csvfile.write(",")
csvfile.write("\n")
请帮我解决这个问题问题。谢谢. 在
编辑:
再解释一下详细信息。这里我需要添加第一节(mono,dono等)将被附加。在
这里的规则是,除非我遇到一个新的“break”类,否则该类中的文本应该附加到该类下面的任何tr中。在
既然你的新问题实际上是一个与原始问题完全不同的问题,这里有一个完全不同的答案:
我假设一行要么正好是1个“break”列,要么是1个或多个常规列。如果这些假设不成立,可以修改代码。在
另外,如果
join
函数中的生成器表达式使您感到困惑,那么可以将相同的内容重写为显式循环:打印标题;然后为每个列打印该列;然后打印换行符。在既然你要求解释
'break' in cols[0].get('class', [])
,我就把它分解。在cols
是当前tr
节点中每个td
节点的BS4Tag
对象的list
。在cols[0]
是第一个。在cols[0].get('class', [])
将Tag
对象视为字典,如the docs所述,并对其调用熟悉的get(key, defaultvalue)
方法。Tag
属性总是返回list
。BS3将为<td class='foo bar'>
返回'foo bar'
,为<td class='foo' class='bar'>
返回{['foo', 'bar']
。在cols[0].get('class', [])
对于<td class='break'>
的情况是['break']
,对于示例输入中的所有其他情况,[]
。在如上所述,我假设一行要么正好是1个“break”列,要么是1个或多个常规列。你可以看到我在代码中使用这些假设的地方。但如果这些假设被打破,你还没有告诉我们足够多的信息来知道你在这些情况下想要做什么。在
如果有没有列的行,显然
cols[0]
将引发一个IndexError
。但你必须决定在这种情况下该怎么做。它应该什么都不做吗?只打印页眉?更改为在我们看到标题行之前不打印任何内容的状态?不管你怎么决定,编码都应该很容易。在如果有任何行的标题后跟普通行,则将忽略普通行。如果有任何不是行中第一列的标题,它们将被视为普通值。如果在同一行中有多个标题,则将忽略除第一个外的所有标题。等等。在每种情况下,这可能是什么,也可能不是什么。但是在你能写代码之前,你必须决定你想要什么。在
使用内置的
csv
模块处理CSV文件。这比手动操作要容易得多。在至于您的问题,这是因为您的
csvfile.write('\n')
缩进太多,所以数据的写入方式与表中显示的一样。做一个发电机,它应该可以工作:您是否尝试过取消缩进
csvfile.write("\n")
,以便它出现在表循环的末尾,而不是tr循环的末尾?在相关问题 更多 >
编程相关推荐