利用Python實(shí)現(xiàn)翻譯HTML中的文本字符串
相信大家都用過瀏覽器的翻譯網(wǎng)頁功能,例如對于下圖這個英文網(wǎng)頁:
一鍵翻譯成中文以后是這樣的:
你可能會覺得這個功能很簡單,不就是字符串替換嗎?那你可以試一試把下面這個HTML片段中的<p>
標(biāo)簽下面的英文翻譯成中文。其它標(biāo)簽中的不要改動:
<div> ?<p>if?you?want?to?parse?date?and?time,?your?could?use?<em>datetime</em>,?by?use?this?library,?you?can?generate?now?time?by?one?line?code?<span>datetime.datetime.now()</span>?this?is?so?easy.</p> </div>
在<em>
標(biāo)簽中的datetime
和<span>
標(biāo)簽中的datetime.datetime.now()
不需要翻譯。
你一拍腦袋,馬上寫出了下面這幾行代碼(假設(shè)你已經(jīng)有了一個現(xiàn)成的translate()
函數(shù),傳入英文,輸出中文):
from?lxml.html?import?fromstring source?=?'''<div> ?<p>if?you?want?to?parse?date?and?time,?your?could?use?<em>datetime</em>,?by?use?this?library,?you?can?generate?now?time?by?one?line?code?<span>datetime.datetime.now()</span>?this?is?so?easy.</p> </div> ''' selector?=?fromstring(source) text_list?=?selector.xpath('//p/text()') for?text?in?text_list: ????chinese?=?translate(text) ????...
當(dāng)你寫到這里,你應(yīng)該會愣一下。因?yàn)槟阃蝗话l(fā)現(xiàn)一個問題,怎么把中文替換回去?
不用嘗試去百度了。在今天(2022-06-20)之前,整個中文網(wǎng)絡(luò)里面,你找不到解決方法。
一個比較笨的辦法是直接對原始的HTML字符串進(jìn)行文本替換:
for?text?in?text_list: ????chinese?=?translate(text) ????source?=?source.replace(text,?chinese)
但這樣做,效率非常低。因?yàn)槟阋煌呙枵麄€HTML字符串。一般一個中型網(wǎng)站的HTML就有幾千上萬行,十幾二十萬個字符。你每翻譯一小段就全文替換一次,這個時間會非常漫長。
那有沒有辦法只對當(dāng)前這一個<p>
標(biāo)簽里面的文本進(jìn)行替換呢?關(guān)鍵的問題來了,你替換可以,但是怎么才能不影響這個<p>
標(biāo)簽下面的兩個子標(biāo)簽?要保證文本和子標(biāo)簽的相對位置不改變。
如果<p>
標(biāo)簽下面只有一段文本,沒有子標(biāo)簽,那么非常簡單,如下圖所示:
但現(xiàn)在的問題是,<p>
標(biāo)簽下面有三段文本。每段文本之間還插入了其它的子標(biāo)簽。我們怎么樣對每一段文本進(jìn)行替換,但是又保持文本的相對順序,并且還不能影響子標(biāo)簽?
p.text
這種寫法首先就可以排除了,因?yàn)樗鼪]有辦法指定替換第幾段文本。
你之所以會覺得這個問題很難解決,是因?yàn)槟阌幸粋€錯覺,請看上面這張截圖,我打印了text_list
。打印出來是一個包含字符串的列表。所以你可能會覺得。使用lxml寫Xpath的時候,/text()
返回的總是包含字符串的列表。
但實(shí)際上,返回的列表里面的元素并不是字符串,而是_ElementUnicodeResult
對象。如下圖所示:
不是字符串就簡單了,那么我們可以獲取每一個文本對象的父標(biāo)簽。然后修改父標(biāo)簽下面的文本就可以了。
看到這里,你肯定會問,這三個文本節(jié)點(diǎn)的父標(biāo)簽,不都是同一個<p>
嗎?如果你覺得是,那你就犯了想當(dāng)然的錯誤。我們用代碼來看看:
其實(shí)只有第一段文本的父標(biāo)簽是<p>
。第二段文本的父標(biāo)簽,竟然是<p>
的子標(biāo)簽<em>
。第三段文本的父標(biāo)簽,是<span>
。
等等,如果第二段文本的父標(biāo)簽是<em>
,那么<em>datetime</em>
里面的datetime
的父標(biāo)簽是什么?它的父標(biāo)簽也是<em>
!那么問題來了,<em>
的text()
文本節(jié)點(diǎn),怎么可能又是datetime
,又是<p>
下面的第二段文本呢?
實(shí)際上,<em>
的text()
始終都是datetime
。如下圖所示:
那么,<p>
的第二段文本跟這個<em>
標(biāo)簽是什么關(guān)系?實(shí)際上,這個關(guān)系叫做tail
。如下圖所示:
在一個標(biāo)簽里面,只有第一段text
是它真正的text()
,如果這個標(biāo)簽有子標(biāo)簽,那么位于子標(biāo)簽后面的文本,是這個子標(biāo)簽的tail
。只不過當(dāng)我們在正則表達(dá)式里面寫/text()
的時候,lxml會幫我們把所有子標(biāo)簽的tail
都算作當(dāng)前標(biāo)簽的text。
我們可以使用文本節(jié)點(diǎn)的.is_text
和.is_tail
來判斷它屬于哪種文本。最終運(yùn)行效果如下圖所示:
以上就是利用Python實(shí)現(xiàn)翻譯HTML中的文本字符串的詳細(xì)內(nèi)容,更多關(guān)于Python翻譯HTML中字符串的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python正則過濾字母、中文、數(shù)字及特殊字符方法詳解
這篇文章主要介紹了python正則過濾字母、數(shù)字及特殊字符方法詳解,需要的朋友可以參考下2020-02-02關(guān)于Python中compile() 函數(shù)簡單實(shí)用示例詳解
這篇文章主要介紹了關(guān)于compile() 函數(shù)簡單實(shí)用示例,compile() 函數(shù)將一個字符串編譯為字節(jié)代碼,compile將代碼編譯為代碼對象,應(yīng)用在代碼中可以提高效率,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05pycharm使用技巧之自動調(diào)整代碼格式總結(jié)
這篇文章主要給大家介紹了關(guān)于pycharm使用技巧之自動調(diào)整代碼格式總結(jié)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Softmax函數(shù)原理及Python實(shí)現(xiàn)過程解析
這篇文章主要介紹了Softmax函數(shù)原理及Python實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05解決pycharm無法識別本地site-packages的問題
今天小編就為大家分享一篇解決pycharm無法識別本地site-packages的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10Python面試之os.system()和os.popen()的區(qū)別詳析
Python調(diào)用Shell,有兩種方法:os.system(cmd)或os.popen(cmd)腳本執(zhí)行過程中的輸出內(nèi)容,下面這篇文章主要給大家介紹了關(guān)于Python面試之os.system()和os.popen()區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-06-06