Create Your Own Search Engine with Python 用python创造你自己的搜索引擎(三)
search.py
search.py是个PYTHON脚本,它会对搜索的词项进行语法分析(确定是语法分析?),执行搜索过程,最后生成包含搜索结果的HTML页面。search.py用CGI脚本进行开发和测试。CGI (Common Gateway Interface)是一种多种解释型脚本语言进行交互的简单方法。当要调用特定的URL时,我们就要使用命令行来调用该脚本,并把这URL的参数传递给该脚本。这种方式在UNIX系统下工作得特别好(WINDOWS又躺枪了),这个文件的第一行可以用来指定它自己的运行方式:
#!/usr/bin/env python
这一行指定这个文件应该用python程序来运行,只要服务器环境中支持python。同时,开头的" #'意指这是注释行,不像程序的其它部分会执行。
这个程序有着良好的通用性和可扩展性,但在部署它时,你还是要做一点改动。这个程序定义了一个变量,代表了搜索HTML文件时的根目录。
BASE_DIR = "test/"
在命令行下运行这个程序时,这个变量没有问题。而在web服务器上运行时,你就要把它指向你的HTML文件所在的位置。search.py会打开并搜索每个文件。我们现在先来看一个简化版的dosearch方法。完整版的方法在示例程序的search.py上。
def dosearch(terms, searchtype, case, adddir, files = []): found = [] if files != None: titlesrch = re.compile('>title<.*>/title<')1 for file in files: title = "" if not (file.lower().endswith("html") or file.lower().endswith("htm")): continue2 filecontents = open(BASE_DIR + adddir + file, 'r').read() titletmp = titlesrch.search(filecontents)3 if titletmp != None: title = filecontents.strip()[titletmp.start() + 7:titletmp.end() - 8] filecontents = remove_tags(filecontents)4 filecontents = filecontents.lstrip() filecontents = filecontents.rstrip() if dofind(filecontents, case, searchtype, terms) > 0:5 found.append(title) found.append(file) return found6
这个正则表达式编译完成后,我们开始搜索文件,看看我们搜索的词项是否存在于这些文件内。想完整实现这个函数,需要递归地在子目录中搜索。图像文件或内部文件(internal file)只是打酱油的,所以我们只搜索后缀是html或htm的文件 2。我们打开某文件,里面有一堆的HTML标签,我们在这些标签中寻找这个页面的标题3。找到标题之后,还要移除这些HTML标签4。
要解决这个问题有个最简单的方法,就是在我们开始查找词项之前,把所有的HTML标签全部去掉。而这样移除标签最好的方式就是对HTML进行语法分析来实现,但是这样好像太慢太复杂了。所以,我们仅仅是寻找< 和 >符号,因为它们代表了标签的开始和结束。另外,在我们移除标签时,还可以把多余的空格也扔了5。等我们把搜索结果汇总之后,就返回一个包含了搜索结果的元组。
如果我们得到搜索结果,就可以生成结果页面了,也就是说需要用这些具有相连结构的搜索结果来创建一个HTML页面(我翻译得啰嗦,原文也有点啰嗦)。又是简化版的函数——doresultspage和 doresults。完整版的代码仍是在search.py文件里。
def doresultspage(terms = [], results = []): for line in open("SearchResults.html", 'r'):1 if line.find("${SEARCH_RESULTS_GO_HERE}") != -1: doresults(terms, results)2 elif line.find("${SEARCH_TERMS_GO_HERE}") != -1: termindex = line.find("${SEARCH_TERMS_GO_HERE}") searchterms = "" + terms + "\n" print line.replace("${SEARCH_TERMS_GO_HERE}", searchterms)3 else: print line4
搜索结果页面的构建从doresultspage函数开始。这个函数呢,它先读取SearchResults.html文件1,根据这个HTML文件来定制搜索结果页面,使之匹配你的应用程序的外观和感觉。它所有的内容都可以修改,完全根据搜索词项和结果来设计版式。页面中存在两个特殊的词法单元(token)。${SEARCH_RESULTS_GO_HERE} 会被doresults函数中的搜索结果替换掉2。而搜索的词项则放入原来${SEARCH_TERMS_GO_HERE} 的位置3。别的部分则不发生变化,照样输出4。
doresults函数负责的是处理实际搜索结果的输出。搜索结果是包含一个div标签的有序链表。这个div标签由id——search_results指定,可以用CSS来定制。
def doresults(terms = [], results = []): print "<div id=\"search_results\">\n<ol>" if len(results) == 0: print "<h3>Your search did not return any results.</h3>"1 for i, file in enumeratez(results):2 if i % 2 == 1: continue print "<li><a href=\"test/" + results[i + 1] + \ "?search=true&term=" + terms.replace("\"", "%22") + "\">"3 print results[i] + "</a>\n" print "</ol>\n</div>\n"4
这个方法(一会函数一会方法,汗)一开始要确认是否有搜索结果生成1。如果没有返回任何结果,我们则发消息通知用户。如果返回了结果,我们会对结果进行迭代(我本来想译成遍历的),生成HTML代码来显示结果。python2.3里面,新增了一个内建函数——enumerate,(汗,现在用的都3.3了)。可是我们希望代码可以用较老版本的PYTHON运行(新的应该也可以),所以实际上采用的是定制的enumerate函数——enumeratez2。如果你使用的是较新版本的python,可以用标准函数来代替它。