Gibt es eine Art und Weise Pythonic zwei HTML-Kopfzeilen mit colspans zu fusionieren?
-
07-07-2019 - |
Frage
Ich BeautifulSoup in Python bin mit etwas HTML zu analysieren. Eines der Probleme, mit mir zu tun habe ist, dass ich Situationen, wo die colspans Reihen über Header unterschiedlich sind. (Header Zeilen sind die Zeilen, die die Spaltenüberschriften in meinem Jargon kombiniert werden müssen, um zu bekommen) Das ist eine Spalte darüber oder darunter eine Anzahl von Spalten erstrecken kann und die Worte müssen auf der Grundlage des Spanning hingen oder vorangestellt werden. Nachfolgend finden Sie eine Routine, dies zu tun. Ich verwende BeautifulSoup die colspans zu ziehen und um den Inhalt jeder Zelle in jeder Reihe zu ziehen. longHeader ist der Inhalt der Kopfzeile mit den meisten Einzelteile, ist spanLong eine Liste mit den colspans jedes Element in der Reihe. Dies funktioniert, aber es ist nicht auf der Suche sehr Pythonic.
Alos-es wird nicht funktionieren, wenn die diff <0 sind, kann ich das beheben, dass mit dem gleichen Ansatz, den ich diese bekommen verwendet, um zu arbeiten. Aber bevor ich das tue ich frage mich, ob jemand schnell dies betrachten und deutet auf einen mehr Pythonic Ansatz. Ich bin eine lange Zeit SAS Programmierer und so ich kämpfen, um die Form gut zu brechen Ich werde Code schreiben, als ob ich ein SAS-Makro schreibe.
longHeader=['','','bananas','','','','','','','','','','trains','','planes','','','','']
shortHeader=['','','bunches','','cars','','trucks','','freight','','cargo','','all other','','']
spanShort=[1,1,3,1,3,1,3,1,3,1,3,1,3,1,3]
spanLong=[1,1,3,1,1,1,1,1,1,1,1,1,3,1,3,1,3,1,3]
combinedHeader=[]
sumSpanLong=0
sumSpanShort=0
spanDiff=0
longHeaderCount=0
for each in range(len(shortHeader)):
sumSpanLong=sumSpanLong+spanLong[longHeaderCount]
sumSpanShort=sumSpanShort+spanShort[each]
spanDiff=sumSpanShort-sumSpanLong
if spanDiff==0:
combinedHeader.append([longHeader[longHeaderCount]+' '+shortHeader[each]])
longHeaderCount=longHeaderCount+1
continue
for i in range(0,spanDiff):
combinedHeader.append([longHeader[longHeaderCount]+' '+shortHeader[each]])
longHeaderCount=longHeaderCount+1
sumSpanLong=sumSpanLong+spanLong[longHeaderCount]
spanDiff=sumSpanShort-sumSpanLong
if spanDiff==0:
combinedHeader.append([longHeader[longHeaderCount]+' '+shortHeader[each]])
longHeaderCount=longHeaderCount+1
break
print combinedHeader
Lösung
Sie haben tatsächlich eine Menge in diesem Beispiel geht.
-
Sie haben "over-processed" die Schöne Suppe Tag Objekte Listen zu machen. Lassen Sie sie als Schlagworte.
-
Alle diese Arten von Merge-Algorithmen sind hart. Es hilft, die beiden Dinge werden zusammen symmetrisch zu behandeln.
Hier ist eine Version, die direkt mit den Schönen Suppe Tag Objekten funktionieren soll. Auch dann, wenn diese Version nichts über die Längen der beiden Reihen übernehmen.
def merge3( row1, row2 ):
i1= 0
i2= 0
result= []
while i1 != len(row1) or i2 != len(row2):
if i1 == len(row1):
result.append( ' '.join(row1[i1].contents) )
i2 += 1
elif i2 == len(row2):
result.append( ' '.join(row2[i2].contents) )
i1 += 1
else:
if row1[i1]['colspan'] < row2[i2]['colspan']:
# Fill extra cols from row1
c1= row1[i1]['colspan']
while c1 != row2[i2]['colspan']:
result.append( ' '.join(row2[i2].contents) )
c1 += 1
elif row1[i1]['colspan'] > row2[i2]['colspan']:
# Fill extra cols from row2
c2= row2[i2]['colspan']
while row1[i1]['colspan'] != c2:
result.append( ' '.join(row1[i1].contents) )
c2 += 1
else:
assert row1[i1]['colspan'] == row2[i2]['colspan']
pass
txt1= ' '.join(row1[i1].contents)
txt2= ' '.join(row2[i2].contents)
result.append( txt1 + " " + txt2 )
i1 += 1
i2 += 1
return result
Andere Tipps
Hier ist eine modifizierte Version des Algorithmus. zip wird verwendet, um iterieren kurz Längen und Header und ein Klassenobjekt verwendet wird, zu zählen und iterieren der lang Artikel sowie kombinieren die Header. , während besser geeignet für die innere Schleife ist. (Verzeiht die zu kurzen Namen).
class collector(object):
def __init__(self, header):
self.longHeader = header
self.combinedHeader = []
self.longHeaderCount = 0
def combine(self, shortValue):
self.combinedHeader.append(
[self.longHeader[self.longHeaderCount]+' '+shortValue] )
self.longHeaderCount += 1
return self.longHeaderCount
def main():
longHeader = [
'','','bananas','','','','','','','','','','trains','','planes','','','','']
shortHeader = [
'','','bunches','','cars','','trucks','','freight','','cargo','','all other','','']
spanShort=[1,1,3,1,3,1,3,1,3,1,3,1,3,1,3]
spanLong=[1,1,3,1,1,1,1,1,1,1,1,1,3,1,3,1,3,1,3]
sumSpanLong=0
sumSpanShort=0
combiner = collector(longHeader)
for sLen,sHead in zip(spanShort,shortHeader):
sumSpanLong += spanLong[combiner.longHeaderCount]
sumSpanShort += sLen
while sumSpanShort - sumSpanLong > 0:
combiner.combine(sHead)
sumSpanLong += spanLong[combiner.longHeaderCount]
combiner.combine(sHead)
return combiner.combinedHeader
Vielleicht für Teile des Problems bei der Zip-Funktion aussehen:
>>> execfile('so_ques.py')
[[' '], [' '], ['bananas bunches'], [' '], [' cars'], [' cars'], [' cars'], [' '], [' trucks'], [' trucks'], [' trucks'], [' '], ['trains freight'], [' '], ['planes cargo'], [' '], [' all other'], [' '], [' ']]
>>> zip(long_header, short_header)
[('', ''), ('', ''), ('bananas', 'bunches'), ('', ''), ('', 'cars'), ('', ''), ('', 'trucks'), ('', ''), ('', 'freight'), ('', ''), ('', 'cargo'), ('', ''), ('trains', 'all other'), ('', ''), ('planes', '')]
>>>
enumerate
kann dazu beitragen, einige der komplexen Indizierung mit Zählern zu vermeiden:
>>> diff_list = []
>>> for place, header in enumerate(short_header):
diff_list.append(abs(span_short[place] - span_long[place]))
>>> for place, num in enumerate(diff_list):
if num:
new_shortlist.extend(short_header[place] for item in range(num+1))
else:
new_shortlist.append(short_header[place])
>>> new_shortlist
['', '', 'bunches', '', 'cars', 'cars', 'cars', '', 'trucks', 'trucks', 'trucks', '',...
>>> z = zip(new_shortlist, long_header)
>>> z
[('', ''), ('', ''), ('bunches', 'bananas'), ('', ''), ('cars', ''), ('cars', ''), ('cars', '')...
Auch mehr pythonic Namensgebung kann Klarheit hinzufügen:
for each in range(len(short_header)):
sum_span_long += span_long[long_header_count]
sum_span_short += span_short[each]
span_diff = sum_span_short - sum_span_long
if not span_diff:
combined_header.append...
Ich glaube, ich werde meine eigene Frage zu beantworten, aber ich habe viel Hilfe erhalten. Vielen Dank für all die Hilfe. Ich habe S.Lott Antwort Arbeit nach ein paar kleine Korrekturen. (Sie können so klein sein, wie nicht sichtbar sein (Insider-Witz)). So, jetzt ist die Frage, warum dies mehr Pythonic ist? Ich glaube, ich sehe, dass es weniger dichte / arbeitet mit den rohen Eingängen statt Ableitungen / Ich kann nicht beurteilen, ob es einfacher ist, zu lesen ---> obwohl es leicht zu lesen
S.Lott Antwort- Korrigierte
row1=headerCells[0]
row2=headerCells[1]
i1= 0
i2= 0
result= []
while i1 != len(row1) or i2 != len(row2):
if i1 == len(row1):
result.append( ' '.join(row1[i1]) )
i2 += 1
elif i2 == len(row2):
result.append( ' '.join(row2[i2]) )
i1 += 1
else:
if int(row1[i1].get("colspan","1")) < int(row2[i2].get("colspan","1")):
c1= int(row1[i1].get("colspan","1"))
while c1 != int(row2[i2].get("colspan","1")):
txt1= ' '.join(row1[i1]) # needed to add when working adjust opposing case
txt2= ' '.join(row2[i2]) # needed to add when working adjust opposing case
result.append( txt1 + " " + txt2 ) # needed to add when working adjust opposing case
print 'stayed in middle', 'i1=',i1,'i2=',i2, ' c1=',c1
c1 += 1
i1 += 1 # Is this the problem it
elif int(row1[i1].get("colspan","1"))> int(row2[i2].get("colspan","1")):
# Fill extra cols from row2 Make same adjustment as above
c2= int(row2[i2].get("colspan","1"))
while int(row1[i1].get("colspan","1")) != c2:
result.append( ' '.join(row1[i1]) )
c2 += 1
i2 += 1
else:
assert int(row1[i1].get("colspan","1")) == int(row2[i2].get("colspan","1"))
pass
txt1= ' '.join(row1[i1])
txt2= ' '.join(row2[i2])
result.append( txt1 + " " + txt2 )
print 'went to bottom', 'i1=',i1,'i2=',i2
i1 += 1
i2 += 1
print result
Nun, ich habe eine Antwort jetzt. Ich wurde durch das Denken und beschlossen, dass ich brauchte Teile jede Antwort zu verwenden. Ich muss immer noch herauszufinden, ob ich eine Klasse oder eine Funktion wollen. Aber ich habe den Algorithmus, der ich denke, ist wahrscheinlich mehr Pythonic als alle anderen. Aber, es lehnt sich stark von den Antworten, die einige sehr großzügige Menschen zur Verfügung gestellt. Ich schätze jene viel, weil ich ziemlich viel gelernt haben.
Um die Zeit zu sparen von mit Testfällen mache ich die den vollständigen Code einfügen werde ich mit weg in IDLE worden hämmern und folgen Sie, dass mit einem HTML-Beispieldatei. Anders als eine Entscheidung über Klasse / Funktion machen (und ich muss darüber nachdenken, wie ich diesen Code in meinem Programm verwende) Ich würde gerne Verbesserungen sehen, die den Code mehr Pythonic machen.
from BeautifulSoup import BeautifulSoup
original=file(r"C:\testheaders.htm").read()
soupOriginal=BeautifulSoup(original)
all_Rows=soupOriginal.findAll('tr')
header_Rows=[]
for each in range(len(all_Rows)):
header_Rows.append(all_Rows[each])
header_Cells=[]
for each in header_Rows:
header_Cells.append(each.findAll('td'))
temp_Header_Row=[]
header=[]
for row in range(len(header_Cells)):
for column in range(len(header_Cells[row])):
x=int(header_Cells[row][column].get("colspan","1"))
if x==1:
temp_Header_Row.append( ' '.join(header_Cells[row][column]) )
else:
for item in range(x):
temp_Header_Row.append( ''.join(header_Cells[row][column]) )
header.append(temp_Header_Row)
temp_Header_Row=[]
combined_Header=zip(*header)
for each in combined_Header:
print each
Ok Testdatei Inhalte sind unten Leider habe ich versucht, diese zu befestigen, konnte es aber nicht geschehen:
<TABLE style="font-size: 10pt" cellspacing="0" border="0" cellpadding="0" width="100%">
<TR valign="bottom">
<TD width="40%"> </TD>
<TD width="5%"> </TD>
<TD width="3%"> </TD>
<TD width="3%"> </TD>
<TD width="1%"> </TD>
<TD width="5%"> </TD>
<TD width="3%"> </TD>
<TD width="3%"> </TD>
<TD width="1%"> </TD>
<TD width="5%"> </TD>
<TD width="3%"> </TD>
<TD width="1%"> </TD>
<TD width="1%"> </TD>
<TD width="5%"> </TD>
<TD width="3%"> </TD>
<TD width="1%"> </TD>
<TD width="1%"> </TD>
<TD width="5%"> </TD>
<TD width="3%"> </TD>
<TD width="3%"> </TD>
<TD width="1%"> </TD>
</TR>
<TR style="font-size: 10pt" valign="bottom">
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">FOODS WE LIKE</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2"> </TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2"> </TD>
<TD> </TD>
</TR>
<TR style="font-size: 10pt" valign="bottom">
<TD> </TD>
<TD> </TD>
<TD nowrap align="CENTER" colspan="6">SILLY STUFF</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">OTHER THAN</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="CENTER" colspan="6">FAVORITE PEOPLE</TD>
<TD> </TD>
</TR>
<TR style="font-size: 10pt" valign="bottom">
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">MONTY PYTHON</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">CHERRYPY</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">APPLE PIE</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">MOTHERS</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">FATHERS</TD>
<TD> </TD>
</TR>
<TR style="font-size: 10pt" valign="bottom">
<TD nowrap align="left">Name</TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">SHOWS</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">PROGRAMS</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">BANANAS</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">PERFUME</TD>
<TD> </TD>
<TD> </TD>
<TD nowrap align="right" colspan="2">TOOLS</TD>
<TD> </TD>
</TR>
</TABLE>