2012-03-19 70 views
1

我有一堆不正確格式的中文html文件。它們包含不必要的空格和換行符,它們將在瀏覽器中顯示爲額外的空格。我用lxml編寫了一個腳本來修改html文件。它在簡單的標籤上工作正常,但是我被困在嵌套的標籤上。例如:使用lxml刪除中文HTML文件中的多餘空格

<p>祝你<span>19</span>歲 
    生日快樂。</p> 

將顯示爲瀏覽器爲:

祝你19歲 生日快樂。 

注意額外的空間。這是需要刪除的內容。結果HTML應該是這樣的:

<p>祝你<span>19</span>歲生日快樂。</p> 

我該怎麼做?

請注意,嵌套(如span標籤)可以是任意的,但我不需要考慮嵌套元素中的內容,它們應該保留原樣。只有外部元素中的文本需要格式化。

這是我的本錢:

# -*- coding: utf-8 -*- 

import lxml.html 
import re 

s1 = u"""<p>祝你19歲 
    生日快樂。</p>""" 
p1 = lxml.html.fragment_fromstring(s1) 
print p1.text   # I get the whole line. 
p1.text = re.sub("\s+", "", p1.text) 
print p1.tostring() # spaces are removed. 

s2 = u"""<p>祝你<span>19</span>歲 
    生日快樂。</p>""" 
p2 = lxml.html.fragment_fromstring(s2) 
print p2.text  # I get "祝你" 
print p2.tail  # I get None 
i = p2.itertext() 
print i.next() # I get "祝你" 
print i.next() # I get "19" from <span> 
print i.next() # I get the tailed text, but how do I assemble them back? 
print p2.text_content() # The whole text, but how do I put <span> back? 
+1

這個任務的哪一部分讓你感到困惑?你有什麼嘗試? – Marcin 2012-03-19 09:42:50

+1

@Marcin代碼示例添加。希望現在已經清楚了。 – 2012-03-19 10:32:37

+0

好問題 - 我的頭頂沒有答案,但我最好猜測的是你必須走樹形結構(遞歸或迭代,如你喜歡的),去除額外的空間。 – Marcin 2012-03-19 10:40:39

回答

1

爭議的是,我不知道這是否是可能的,而無需使用HTML/XML解析器,考慮到它看起來是換行的事業來完成。

我建了一個正則表達式查找空白文本中國之間的這種解決方案在這裏的幫助:https://stackoverflow.com/a/2718268/267781

,我不知道是否捕獲所有的字符之間還是較爲任何空白具體的[char]\n\s*[char]是最適合你的問題。

# -*- coding: utf-8 -*- 
import re 

# Whitespace in Chinese HTML 
## Used this solution to create regexp: https://stackoverflow.com/a/2718268/267781 
## \s+ 
fixwhitespace2 = re.compile(u'[\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303a\u303b\u3400-\u4db5\u4e00-\u9fc3\uf900-\ufa2d\ufa30-\ufa6a\ufa70-\ufad9\U00020000-\U0002a6d6\U0002f800-\U0002fa1d](\s+)[\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303a\u303b\u3400-\u4db5\u4e00-\u9fc3\uf900-\ufa2d\ufa30-\ufa6a\ufa70-\ufad9\U00020000-\U0002a6d6\U0002f800-\U0002fa1d]',re.M) 
## \n\s* 
fixwhitespace = re.compile(u'[\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303a\u303b\u3400-\u4db5\u4e00-\u9fc3\uf900-\ufa2d\ufa30-\ufa6a\ufa70-\ufad9\U00020000-\U0002a6d6\U0002f800-\U0002fa1d](\n\s*)[\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303a\u303b\u3400-\u4db5\u4e00-\u9fc3\uf900-\ufa2d\ufa30-\ufa6a\ufa70-\ufad9\U00020000-\U0002a6d6\U0002f800-\U0002fa1d]',re.M) 

sample = u'<html><body><p>\u795d\u4f6019\u5c81\n \u751f\u65e5\u5feb\u4e50\u3002</p></body></html>' 

fixwhitespace.sub('',sample) 

屈服

<html><body><p>祝你19日快樂。</p></body></html> 

然而,這裏是你會如何使用解析器和XPath找換行做到這一點:

# -*- coding: utf-8 -*- 
from lxml import etree 
import re 

fixwhitespace = re.compile(u'[\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303a\u303b\u3400-\u4db5\u4e00-\u9fc3\uf900-\ufa2d\ufa30-\ufa6a\ufa70-\ufad9\U00020000-\U0002a6d6\U0002f800-\U0002fa1d](\n\s*)[\u2e80-\u2e99\u2e9b-\u2ef3\u2f00-\u2fd5\u3005\u3007\u3021-\u3029\u3038-\u303a\u303b\u3400-\u4db5\u4e00-\u9fc3\uf900-\ufa2d\ufa30-\ufa6a\ufa70-\ufad9\U00020000-\U0002a6d6\U0002f800-\U0002fa1d]',re.M) 
sample = u'<html><body><p>\u795d\u4f6019\u5c81\n \u751f\u65e5\u5feb\u4e50\u3002</p></body></html>' 

doc = etree.HTML(sample) 
for t in doc.xpath("//text()[contains(.,'\n')]"): 
    if t.is_tail: 
    t.getparent().tail = fixwhitespace.sub('',t) 
    elif t.is_text: 
    t.getparent().text = fixwhitespace.sub('',t) 

print etree.tostring(doc) 

產量:

<html><body><p>&#31069;&#20320;19&#26085;&#24555;&#20048;&#12290;</p></body></html> 

我很好奇你的工作數據的最佳匹配是什麼。

+0

謝謝!純正則表達式不適用於某些內容,但xpath +正則表達式工作得很好。 – 2012-03-20 03:29:59

+0

*純正則表達式不適用於某些內容* - 我想這會驗證關於正則表達式和HTML/XML的所有警告和警告!我很高興其中一種方法在整個數據集中都是有效的。 – MattH 2012-03-20 08:48:32

2
>>> root = etree.fromstring('<p>祝你<span>19</span>歲\n生日快樂。</p>') 
>>> etree.tostring(root) 
b'<p>&#31069;&#20320;<span>19</span>&#23681;\n&#29983;&#26085;&#24555;&#20048;&#12290;</p>' 

>>> for e in root.xpath('/p/*'): 
... if e.tail: 
...  e.tail = e.tail.replace('\n', '') 
... 

>>> etree.tostring(root) 
b'<p>&#31069;&#20320;<span>19</span>&#23681;&#29983;&#26085;&#24555;&#20048;&#12290;</p>' 
+0

謝謝。我應該多看看xpath。我接受了馬特的答案,因爲它更全面。 – 2012-03-20 03:33:25