利用Python实现翻译HTML中的文本字符串
作者:kingname 发布时间:2022-02-20 23:03:13
相信大家都用过浏览器的翻译网页功能,例如对于下图这个英文网页:
一键翻译成中文以后是这样的:
你可能会觉得这个功能很简单,不就是字符串替换吗?那你可以试一试把下面这个HTML片段中的<p>
标签下面的英文翻译成中文。其它标签中的不要改动:
<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>
标签中的datetime
和<span>
标签中的datetime.datetime.now()
不需要翻译。
你一拍脑袋,马上写出了下面这几行代码(假设你已经有了一个现成的translate()
函数,传入英文,输出中文):
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)
...
当你写到这里,你应该会愣一下。因为你突然发现一个问题,怎么把中文替换回去?
不用尝试去百度了。在今天(2022-06-20)之前,整个中文网络里面,你找不到解决方法。
一个比较笨的办法是直接对原始的HTML字符串进行文本替换:
for text in text_list:
chinese = translate(text)
source = source.replace(text, chinese)
但这样做,效率非常低。因为你要不停扫描整个HTML字符串。一般一个中型网站的HTML就有几千上万行,十几二十万个字符。你每翻译一小段就全文替换一次,这个时间会非常漫长。
那有没有办法只对当前这一个<p>
标签里面的文本进行替换呢?关键的问题来了,你替换可以,但是怎么才能不影响这个<p>
标签下面的两个子标签?要保证文本和子标签的相对位置不改变。
如果<p>
标签下面只有一段文本,没有子标签,那么非常简单,如下图所示:
但现在的问题是,<p>
标签下面有三段文本。每段文本之间还插入了其它的子标签。我们怎么样对每一段文本进行替换,但是又保持文本的相对顺序,并且还不能影响子标签?
p.text
这种写法首先就可以排除了,因为它没有办法指定替换第几段文本。
你之所以会觉得这个问题很难解决,是因为你有一个错觉,请看上面这张截图,我打印了text_list
。打印出来是一个包含字符串的列表。所以你可能会觉得。使用lxml写Xpath的时候,/text()
返回的总是包含字符串的列表。
但实际上,返回的列表里面的元素并不是字符串,而是_ElementUnicodeResult
对象。如下图所示:
不是字符串就简单了,那么我们可以获取每一个文本对象的父标签。然后修改父标签下面的文本就可以了。
看到这里,你肯定会问,这三个文本节点的父标签,不都是同一个<p>
吗?如果你觉得是,那你就犯了想当然的错误。我们用代码来看看:
其实只有第一段文本的父标签是<p>
。第二段文本的父标签,竟然是<p>
的子标签<em>
。第三段文本的父标签,是<span>
。
等等,如果第二段文本的父标签是<em>
,那么<em>datetime</em>
里面的datetime
的父标签是什么?它的父标签也是<em>
!那么问题来了,<em>
的text()
文本节点,怎么可能又是datetime
,又是<p>
下面的第二段文本呢?
实际上,<em>
的text()
始终都是datetime
。如下图所示:
那么,<p>
的第二段文本跟这个<em>
标签是什么关系?实际上,这个关系叫做tail
。如下图所示:
在一个标签里面,只有第一段text
是它真正的text()
,如果这个标签有子标签,那么位于子标签后面的文本,是这个子标签的tail
。只不过当我们在正则表达式里面写/text()
的时候,lxml会帮我们把所有子标签的tail
都算作当前标签的text。
我们可以使用文本节点的.is_text
和.is_tail
来判断它属于哪种文本。最终运行效果如下图所示:
来源:https://mp.weixin.qq.com/s/Hi-yGN9zwbLbqdlckSgJcg


猜你喜欢
- 前言很多开发同学对SQL优化如数家珍,却对MySQL架构一知半解。岂不是只见树叶,不见森林,终将陷入细节中不能自拔。今天就一块学习MySQL
- 使用Django框架搭建后端服务器,后台接收前端传递过来xlsx的文件,直接将前端传递的文件转化为DataFrame或直接将文件保存。url
- 从有道词典网页获取某单词的中文解释。import reimport urllibword=raw_input('input a wo
- 利用js实现点击一张图片,直接上传到指定的action,方法简单,一看就会了,只需要用户点击图片一次就可以实现图片上传功能。主要用到了onc
- 如图所示,有一个test文件夹,里面有3个子文件夹,每个子文件夹中有若干图片文件#场景1 读取一个文件夹中所有文件,存入到一个list表中#
- 何为聚类分析聚类分析或聚类是对一组对象进行分组的任务,使得同一组(称为聚类)中的对象(在某种意义上)与其他组(聚类)中的对象更相似(在某种意
- 前一阵,我在为朋友编写一个源代码监控程序的时候,发现了一个 Python 领域非常简单好用的图形界面库。说起图形界面库,你可能会想到 TkI
- 一个普通WEB站点的页面常常需要查询N条SQL语句后才能得出页面结果,当网站访问速度慢而前端做了大量优化工作以后,数据库瓶颈的查找也是WEB
- 静态方法:将下面的代码复制到<body>~</body>内 程序代码 <table cellpadd
- 概述Go 语言中的 new 和 make 一直是新手比较容易混淆的东西,咋一看很相似。不过解释两者之间的不同也非常容易。new 的主要特性首
- 将Django与MongoDB集成在不更改Django ORM的情况下,将MongoDB用作Django项目的后端数据库。使用Django
- 今天小池提出一个问题讨论,如何使分页做的更友好。做了一些调研和思考,做了些总结。分页在电商网站3级页、搜索结果页面等信息量大的页面是很重要的
- 本文实例讲述了基于进程内通讯的python聊天室实现方法。分享给大家供大家参考。具体如下:#!/usr/bin/env python# Ad
- 概述在pytorch中有两种方式可以保存推理模型,第一种是只保存模型的参数,比如parameters和buffers;另外一种是保存整个模型
- 函数的迭代器函数的强大功能叫做迭代器,Python里面最具威力的功能之一。迭代器我们听起来会感觉非常陌生,在list、tuple都有用到它,
- 用了on error resume next则在这句往后的代码就算出错也会继续执行具体有没有错可以用err.number来判断err.num
- 我们有时候看到一些文章因为一行的字符超长而把一些表格或DIV撑开或字符写到溢出了.如何防止表格防止撑开,表格不被内容撑开,单行字符超长div
- Rosenbrock函数的定义如下:其函数图像如下:我分别使用梯度下降法和牛顿法做了寻找Rosenbrock函数的实验。梯度下降梯度下降的更
- 方法1:import requestsurl = "http://www.xxxx.net/login"#参数拼凑,附件
- 本文实例为大家分享了用vue实现加载页的具体代码,供大家参考,具体内容如下<template>? ? <div class