2017-08-23 2 views
1

Hallo ich möchte mir ein kleines Helfer-Tool in Python codieren es den folgenden Inhalt verarbeiten soll:Python Regex Scrape & Ersetzen String

<tr> 
<td><p>L1</p></td> 
<td><p>(4.000x2.300x500;   4,6m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.221 kg</p></td> 
</tr> 
<tr> 
<td><p>L2</p></td> 
<td><p>(4.250x2.300x500;   4,9m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.279 kg</p></td> 
</tr> 
<tr> 
<td><p>L3</p></td> 
<td><p>(4.500x2.300x500;   5,2m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.321 kg</p></td> 
</tr> 
<tr> 
<td><p>L4</p></td> 
<td><p>(4.750x2.300x500;   5,5m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.364 kg</p></td> 
</tr> 

Es sollte die &nbsp; jeder Tabellenzeile mit dem Volumen ersetzen in dieser Fall alles zwischen den; und das) in dem zweiten Tabellendatenfeld jeder Reihe.

Ich fing an, es in Python so zu kodieren, und ich könnte bereits den Datenträger mit einer Regex-Anweisung abkratzen, aber meine Logik endet damit, wie man die Werte an die richtige Stelle setzt. irgendeine Idee ? hier ist mein Code

import BeautifulSoup 
import re 

with open('3mmcontainer.html') as f: 
    content = f.read() 
f.close() 

#print content 

contentsoup = BeautifulSoup.BeautifulSoup(content) 

for tablerow in contentsoup.findAll('tr'): 
    inhalt = str(tablerow.contents[3]) 
    print inhalt 


    match = re.findall('\;(.*?)\)', inhalt) 


    print match 
# for x in match: 
# volumen = x.lstrip() 
# print volumen 

    #f = open('3mmcontainer.html', 'w') 
    #newdata = f.replace("&nbsp;", volumen) 
    #f.write(newdata) 
    #f.close() 


#m = re.search('\;(.*?)\)', inhalt) 
# print m 

# volumen = re.compile(r'\;(.*?)\)') 
# volumen.match(tablerow.contents[3]) 

Antwort

3

NB: Sie müssen nicht close() anrufen müssen, weil die with Aussage, die es für Sie tun.

können Sie eine einfache Funktion verwenden, um jede Zeile (<tr/>) zu transformieren:

import re 


def parse_inhalt(content): 
    td_list = re.findall(r"<td>(?:(?!</td>).)+</td>", content) 
    vol_content = td_list[1] 
    vol = re.findall(r";([^)]+)", vol_content)[0] 
    return content.replace("&nbsp;", vol) 

Der Code ist einfach:

  • jede Zelle Extrakt in td_list
  • Holen Sie sich den Inhalt der zweite Zelle, die das Band enthält
  • Finden Sie das Volumen zwischen ";" und ")" (ohne die Zeichen)
  • Ersetzen Sie die &nbsp; durch die Volumen

Zum Beispiel:

inhalt = u"""\ 
<tr> 
<td><p>L4</p></td> 
<td><p>(4.750x2.300x500; 5,5m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.364 kg</p></td> 
</tr>""" 

print(parse_inhalt(inhalt)) 

Sie erhalten:

<tr> 
<td><p>L4</p></td> 
<td><p>(4.750x2.300x500; 5,5m³)</p></td> 
<td><p> 5,5m³</p></td> 
<td><p> 1.364 kg</p></td> 
</tr> 

Sie fallen kann die Räume, die durch Verwendung von:

vol = re.findall(r";\s*([^)]+)", vol_content)[0] 
1

Ein alternativer Ansatz.

Zuerst alle Tabellenzellen finden und die p Elemente in ihnen. Sie wissen, dass die Elemente durch die Anwesenheit von innerhalb ihrer text s gekennzeichnet sind, so achten Sie darauf, und Sie wissen, dass Sie die Elemente ändern müssen, die sofort folgen. Dann arrangieren Sie, um den Bereich zu erfassen, wenn Sie darauf stoßen, notieren Sie die Ordnungszahl des Elements p und ändern Sie dann, wenn Sie auf das nächste Element stoßen, text, indem Sie area seinem Attribut string zuweisen.

Wenn Sie regex bevorzugen, dann können Sie diese area für die Berechnung verwenden:

area = bs4.re.search(r';\s+([^\)]+)', p.text).groups(0)[0] 

.

>>> import bs4 
>>> soup = bs4.BeautifulSoup(open('temp.htm').read(), 'lxml') 
>>> k = None 
>>> for i, p in enumerate(soup.select('td > p')): 
...  if 'm³' in p.text: 
...   area = p.text[1+p.text.rfind(';'):-1].strip() 
...   k = i 
...  if k and i == k + 1: 
...   p.string = area 
... 
>>> soup 
<html><body><tr> 
<td><p>L1</p></td> 
<td><p>(4.000x2.300x500; 4,6m³)</p></td> 
<td><p>4,6m³</p></td> 
<td><p> 1.221 kg</p></td> 
</tr> 
<tr> 
<td><p>L2</p></td> 
<td><p>(4.250x2.300x500; 4,9m³)</p></td> 
<td><p>4,9m³</p></td> 
<td><p> 1.279 kg</p></td> 
</tr> 
<tr> 
<td><p>L3</p></td> 
<td><p>(4.500x2.300x500; 5,2m³)</p></td> 
<td><p>5,2m³</p></td> 
<td><p> 1.321 kg</p></td> 
</tr> 
<tr> 
<td><p>L4</p></td> 
<td><p>(4.750x2.300x500; 5,5m³)</p></td> 
<td><p>5,5m³</p></td> 
<td><p> 1.364 kg</p></td> 
</tr></body></html> 
>>> 
1

wenn brute force regex akzeptabel

s=''' 
<tr> 
<td><p>L1</p></td> 
<td><p>(4.000x2.300x500; 4,6m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.221 kg</p></td> 
</tr> 
<tr> 
<td><p>L2</p></td> 
<td><p>(4.250x2.300x500; 4,9m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.279 kg</p></td> 
</tr> 
<tr> 
<td><p>L3</p></td> 
<td><p>(4.500x2.300x500; 5,2m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.321 kg</p></td> 
</tr> 
<tr> 
<td><p>L4</p></td> 
<td><p>(4.750x2.300x500; 5,5m³)</p></td> 
<td><p>&nbsp;</p></td> 
<td><p> 1.364 kg</p></td> 
</tr> 
''' 

import re 

p=r'(\([0-9x.]+)(; +)([0-9,m³]+)(\)</p></td>\n <td><p>)(&nbsp;)' 

# not sure which output is preferred 
x = re.sub(p, '\g<1>\g<2>\g<3>\g<4>\g<3>', s) 
print(x) 

y = re.sub(p, '\g<1>\g<4>\g<3>', s) 
print(y)