用一些简单的脚本, 可以很容易地清理文档和其它大量的 html 文件但是首先你需要解析它们
图片由 Jason Baker 为 Opensource.com 所作
作为 Scribus 文档团队的长期成员, 我要随时了解最新的源代码更新, 以便对文档进行更新和补充 我最近在刚升级到 Fedora 27 系统的计算机上使用 Subversion 进行检出操作时, 对于下载该文档所需要的时间我感到很惊讶, 文档由 HTML 页面和相关图像组成 我恐怕该项目的文档看起来比项目本身大得多, 并且怀疑其中的一些内容是僵尸文档不再使用的 HTML 文件以及 HTML 中无法访问到的图像
我决定为自己创建一个项目来解决这个问题 一种方法是搜索未使用的现有图像文件 如果我可以扫描所有 HTML 文件中的图像引用, 然后将该列表与实际图像文件进行比较, 那么我可能会看到不匹配的文件
<img src="images/edit_shapes.png" ALT="Edit examples" ALIGN=left>
我对 src= 之后的第一组引号之间的部分很感兴趣 在寻找了一些解决方案后, 我找到一个名为 BeautifulSoup 的 Python 模块 脚本的核心部分如下所示:
- soup = BeautifulSoup(all_text, 'html.parser')
- match = soup.findAll("img")
- if len(match)> 0:
- for m in match:
- imagelist.append(str(m))
我们可以使用这个 findAll 方法来挖出图片标签 这是一小部分输出:
<img src="images/pdf-form-ht3.png"/><img src="images/pdf-form-ht4.png"/><img src="images/pdf-form-ht5.png"/><img src="images/pdf-form-ht6.png"/><img align="middle" alt="GSview - Advanced Options Panel" src="images/gsadv1.png" title="GSview - Advanced Options Panel"/><img align="middle" alt="Scribus External Tools Preferences" src="images/gsadv2.png" title="Scribus External Tools Preferences"/>
到现在为止还挺好我原以为下一步就可以搞定了, 但是当我在脚本中尝试了一些字符串方法时, 它返回了有关标记的错误而不是字符串的错误 我将输出保存到一个文件中, 并在 KWrite 中进行编辑 KWrite 的一个好处是你可以使用正则表达式 (regex) 来做查找和替换操作, 所以我可以用 \n<img 替换 <img, 这样可以看得更清楚 KWrite 的另一个好处是, 如果你用正则表达式做了一个不明智的选择, 你还可以撤消
但我认为, 肯定有比这更好的东西, 所以我转而使用正则表达式, 或者更具体地说 Python 的 re 模块 这个新脚本的相关部分如下所示:
- match = re.findall(r'src="(.*)/>', all_text)
- if len(match)>0:
- for m in match:
- imagelist.append(m)
它的一小部分输出如下所示:
images/cmcanvas.png"title="Context Menu for the document canvas"alt="Context Menu for the document canvas"/></td></tr></table><br images/eps-imp1.png" title="EPS preview in a file dialog" alt="EPS preview in a file dialog" images/eps-imp5.png"title="Colors imported from an EPS file"alt="Colors imported from an EPS file"images/eps-imp4.png" title="EPS font substitution" alt="EPS font substitution" images/eps-imp2.png"title="EPS import progress"alt="EPS import progress"images/eps-imp3.png" title="Bitmap conversion failure" alt="Bitmap conversion failure"
乍一看, 它看起来与上面的输出类似, 并且附带有去除图像的标签部分的好处, 但是有令人费解的是还夹杂着表格标签和其他内容 我认为这涉及到这个正则表达式 src="(.*)/>, 这被称为_贪婪_, 意味着它不一定停止在遇到 /> 的第一个实例我应该补充一点, 我也尝试过 src="(.*)", 这真的没有什么更好的效果, 我不是一个正则表达式专家(只是做了这个), 找了各种方法来改进这一点但是并没什么用
做了一系列的事情之后, 甚至尝试了 Perl 的 HTML::Parser 模块, 最终我试图将这与我为 Scribus 编写的一些脚本进行比较, 这些脚本逐个字符的分析文本内容, 然后采取一些行动 为了最终目的, 我终于想出了所有这些方法, 并且完全不需要正则表达式或 HTML 解析器 让我们回到展示的那个 img 标签的例子
<img src="images/edit_shapes.png" ALT="Edit examples" ALIGN=left>
我决定回到 src= 这一块 一种方法是等待 s 出现, 然后看下一个字符是否是 r, 下一个是 c, 下一个是否 = 如果是这样, 那就匹配上了! 那么两个双引号之间的内容就是我所需要的 这种方法的问题在于需要连续识别上面这样的结构 一种查看代表一行 HTML 文本的字符串的方法是:
for c in all_text:
但是这个逻辑太乱了, 以至于不能持续匹配到前面的 c, 还有之前的字符, 更之前的字符, 更更之前的字符
最后, 我决定专注于 = 并使用索引方法, 以便我可以轻松地引用字符串中的任何先前或将来的字符 这里是搜索部分:
- index = 3
- while index <linelength:
- if (all_text[index] == '='):
- if (all_text[index-3] == 's') and (all_text[index-2] == 'r') and (all_text[index-1] == 'c'):
- imagefound(all_text, imagelist, index)
- index += 1
- else:
- index += 1
- else:
- index += 1
我用第四个字符开始搜索(索引从 0 开始), 所以我在下面没有出现索引错误, 并且实际上, 在每一行的第四个字符之前不会有等号 第一个测试是看字符串中是否出现了 =, 如果没有, 我们就会前进 如果我们确实看到一个等号, 那么我们会看前三个字符是否是 sr 和 c 如果全都匹配了, 就调用函数 imagefound:
- def imagefound(all_text, imagelist, index):
- end = 0
- index += 2
- newimage = ''
- while end == 0:
- if (all_text[index] != '"'):
- newimage = newimage + all_text[index]
- index += 1
- else:
- newimage = newimage + '\n'
- imagelist.append(newimage)
- end = 1
- return
我们给函数发送当前索引, 它代表着 = 我们知道下一个字符将会是 ", 所以我们跳过两个字符, 并开始向名为 newimage 的控制字符串添加字符, 直到我们发现下一个", 此时我们完成了一次匹配 我们将字符串加一个换行符 (\n) 添加到列表 imagelist 中并返回(return), 请记住, 在剩余的这个 HTML 字符串中可能会有更多图片标签, 所以我们马上回到搜索循环中
以下是我们的输出现在的样子:
- images/text-frame-link.png
- images/text-frame-unlink.png
- images/gimpoptions1.png
- images/gimpoptions3.png
- images/gimpoptions2.png
- images/fontpref3.png
- images/font-subst.png
- images/fontpref2.png
- images/fontpref1.png
- images/dtp-studio.png
啊, 干净多了, 而这只花费几秒钟的时间 我本可以将索引前移 7 步来剪切 images/ 部分, 但我更愿意把这个部分保存下来, 以确保我没有剪切掉图像文件名的第一个字母, 这很容易用 KWrite 编辑成功 你甚至不需要正则表达式 做完这些并保存文件后, 下一步就是运行我编写的另一个脚本 sortlist.py:
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # sortlist.py
- import os
- imagelist = []
- for line in open('/tmp/imagelist_parse4.txt').xreadlines():
- imagelist.append(line)
- imagelist.sort()
- outfile = open('/tmp/imagelist_parse4_sorted.txt', 'w')
- outfile.writelines(imagelist)
- outfile.close()
这会读取文件内容, 并存储为列表, 对其排序, 然后另存为另一个文件 之后, 我可以做到以下几点:
ls /home/gregp/development/Scribus15x/doc/en/images/*.png> '/tmp/actual_images.txt'
然后我需要在该文件上运行 sortlist.py, 因为 ls 方法的排序与 Python 不同 我原本可以在这些文件上运行比较脚本, 但我更愿意以可视方式进行操作 最后, 我成功找到了 42 个图像, 这些图像没有来自文档的 HTML 引用
这是我的完整解析脚本:
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # parseimg4.py
- import os
- def imagefound(all_text, imagelist, index):
- end = 0
- index += 2
- newimage = ''
- while end == 0:
- if (all_text[index] != '"'):
- newimage = newimage + all_text[index]
- index += 1
- else:
- newimage = newimage + '\n'
- imagelist.append(newimage)
- end = 1
- return
- htmlnames = []
- imagelist = []
- tempstring = ''filenames = os.listdir('/home/gregp/development/Scribus15x/doc/en/')
- for name in filenames:
- if name.endswith('.html'):
- htmlnames.append(name)
- #print htmlnames
- for htmlfile in htmlnames:
- all_text = open('/home/gregp/development/Scribus15x/doc/en/' + htmlfile).read()
- linelength = len(all_text)
- index = 3
- while index < linelength:
- if (all_text[index] == '='):
- if (all_text[index-3] == 's') and (all_text[index-2] == 'r') and
- (all_text[index-1] == 'c'):
- imagefound(all_text, imagelist, index)
- index += 1
- else:
- index += 1
- else:
- index += 1
- outfile = open('/tmp/imagelist_parse4.txt', 'w')
- outfile.writelines(imagelist)
- outfile.close()
- imageno = len(imagelist)
- print str(imageno) + "images were found and saved"
脚本名称为 parseimg4.py, 这并不能真实反映我陆续编写的脚本数量(包括微调的和大改的以及丢弃并重新开始写的) 请注意, 我已经对这些目录和文件名进行了硬编码, 但是很容易变得通用化, 让用户输入这些信息 同样, 因为它们是工作脚本, 所以我将输出发送到 /tmp 目录, 所以一旦重新启动系统, 它们就会消失
这不是故事的结尾, 因为下一个问题是: 僵尸 HTML 文件怎么办? 任何未使用的文件都可能会引用图像, 不能被前面的方法所找出 我们有一个 menu.xml 文件作为联机手册的目录, 但我还需要考虑 TOC(LCTT 译注: TOC 是 table of contents 的缩写)中列出的某些文件可能引用了不在 TOC 中的文件, 是的, 我确实找到了一些这样的文件
来源: http://igeekbar.com/igeekbar/post/1072.htm