原文出自:http://www.codeproject.com/KB/applications/SearchDotnet.aspx

作者:Stevan Rodrigues

翻译:张远山

站点搜索引擎搜索整个页面(动态页面也可以)中的关键字或关键词并且计算关键字或关键词在页面中出现的次数,然后按最高匹配优先把结果显示出来。

l         下载最新版本的示例工程 (VB.NET) - 67 Kb

l         下载读写XML的示例工程 (VB.NET) - 88 Kb

l         下载最新版本的示例工程(Visual Studio .NET 非必须的) - 52 Kb

l         下载最早版本的示例工程 (C #) - 28 Kb

引言

站点搜索引擎搜索整个页面(动态页面也可以)中的关键字或关键词并且计算关键字或关键词在页面中出现的次数,然后按最高匹配优先把结果显示出来。你可以轻易地把文件扩展名放到web.congig文件标记的地方,搜索模块将搜索所有符合这些文件扩展名的文件。你不想搜索的文件或文件夹也可以放在web.config标记的地方,这些文件和文件夹将不会被搜索。现在你还可以选择编码格式。

这篇已更新的文章包含全球化和优化代码的提示

注:此搜索引擎适最合于小站点。你也可以使用正则表达式和改变这些代码来搜索内部网。对于大型网站你需要周期性的写入XML然后从XML中读取。我已经在文章的后面部分提供了使用说明。我也加入了一个读写XML的示例工程

背景

搜索引擎帮助用户找到他感兴趣的页面。当我在做ASP.NET项目的时候,我一定把搜索模块加到网站中去。我曾经有一个ASP的而非.NET的,这个搜索引擎就是因此而产生的。我的第一个版本仅仅是一个简单的Web窗体,还没有充分使用.NET 语言面向对象的特性。在空闲时间,我使我的代码最大限度地使用面向对象语言。在这篇文章中,我在实际经验和不同作者良好实践建议基础上进一步加强我的设计。

来自北京的 宋涛先生带着怎样把模块转成中文的疑问联系了我。在他的帮助下我增强代码可以支持其他语言。一些用户在把SiteSearch.asp放到网站根目录的时候也遇到了一些问题,我已经更改了代码修正了错误。

源代码概述

网站搜索引擎结构如下所示:

定义类和创建类示例的能力是面向对象语言的最重要的特性之一。在紧接着的章节中,我们将讲述搜索模块中用到的类。

类名

描述

SiteSearch

Web窗体使用的类,用户可以通过某些词搜索网站

Searches.CleanHtml

用来清理HTML内容的类

Searches.FileContent

从HTML文件获取内容的类

Searches.Page

用来存储页面中数据的类

Searches.PagesDataset

用来在dataset中创建和存储结果的类

Searches.Site

用来读取网站配置的类

Searches.UserSearch

用来为每个用户存储搜索信息的类

SiteSearch.aspx

Web窗体是微软的.NET首创的令人激动的特性之一。SiteSearch.aspx是一个Web窗体也是搜索模块的起始页面。

一个Web窗体页面由页面(ASPX 文件)和后台代码(.aspx.cs 文件或.aspx.vb文件)组成。我们的Web窗体由SiteSearch..aspx和SiteSearch.aspx.vb。下面我将处理这两个页面同时涉及一些Web窗体的主要元素。

ASP.NET是一个事件驱动的设计环境,在下来的章节我们将会讲述一些事件的处理和方法

Page_Load

服务器控件在Page对象被加载,view state信息在此时也是可用的。Page_Load事件检测sSite是否为nothing并且把Session(“Site”)变量给它赋值。

Private Sub Page_Load(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Load

If IsNothing(sSite) Then

sSite = Session("Site")

End If

End Sub

srchbtn_Click

当搜索按钮被点击后搜索按钮的事件将被激活。这里我们编写代码来改变控件设置或在页面中显示文本。我们检测搜索是否包含文本然后调用SearchSite方法。DisplayContent()被调用来给web页面的不同控件赋值。

'*********************************************************

'

' srchbtn_Click 事件

'

' 在此事件中增加代码.

'

'**********************************************************

Private Sub srchbtn_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles srchbtn.Click

Dim strSearchWords As String

'如果用户没有输入要搜索的词

'则不执行文件搜索程序

pnlSearchResults.Visible = False

strSearchWords = Trim(Request.Params("search"))

If Not strSearchWords.Equals("") Then

Searchs.Site.ApplicationPath = String.Format("http://{0}{1}",

Request.ServerVariables("HTTP_HOST"), Request.ApplicationPath)

sSite = SearchSite(strSearchWords)

Session("Site") = sSite

dgrdPages.CurrentPageIndex = 0

DisplayContent()

End If

End Sub

DisplayContent

DisplayContent()被调用来给web页面的不同控件赋值。通过调用BindDataGrid方法来设置DataGrid的内容。使用ViewState(“SortExpression”)来设置排序方法的描述。

'*********************************************************************

'

' DisplayContent 方法

'

' 数据被绑定到各个地方

'

'*********************************************************************

Private Sub DisplayContent()

If Not IsNothing(sSite.PageDataset) Then

pnlSearchResults.Visible = True

lblSearchWords.Text = sSite.SearchWords

If ViewState("SortExpression") Is Nothing Then

ViewState("SortExpression") = "MatchCount Desc"

End If

BindDataGrid(ViewState("SortExpression"))

lblTotalFiles.Text = sSite.TotalFilesSearched

lblFilesFound.Text = sSite.TotalFilesFound

End If

End Sub

搜索

搜索的主要调用在这个方法中进行。UserSearch类保存所有搜索信息和搜索结果,之后我们将讲述这个类。UserSearch类对象也就是srchSite被创建,它的属性如SearchWords和SearchCriteria被赋值,并且srchSite.Search方法被调用。

'************************************************************

'

' SearchSite 方法

'

' sSite.PageDataset 用来给dataset设置值。.

'

'************************************************************

Private Function SearchSite(ByVal strSearch_

As String) As Searchs.UserSearch

Dim srchSite As Searchs.UserSearch

srchSite = New Searchs.UserSearch()

'Read in all the search words into one variable

srchSite.SearchWords = strSearch

If Phrase.Checked Then

srchSite.SearchCriteria = Searchs.SearchCriteria.Phrase

ElseIf AllWords.Checked Then

srchSite.SearchCriteria = Searchs.SearchCriteria.AllWords

ElseIf AnyWords.Checked Then

srchSite.SearchCriteria = Searchs.SearchCriteria.AnyWords

End If

srchSite.Search(Server.MapPath("./"))

Return srchSite

End Function

DataGrid

DataGrid控件是代表一个多列的、完全模板化的表格,在众多的数据绑定控件中它的功能更加强大,而且DataGrid控件是ASP.NET为数据报表所特制的,因此我使用它来显示搜索结果。因为本文的重点是讲内部网络的搜索引擎,因此我只给出使用DataGrid特性的简单介绍。

数据绑定

数据绑定是从数据源中获取数据并且动态联结到可视化组件的属性的过程。因为DataGrid同时处理(只是在内存中有)更多的条目,你应该明确地把数据集合联结到DataGrid——那就是,数据源。

DataGrid的内容通过设置它的DataSource属性来实现。整个搜索结果被保存在sSite.PageDataset.Tables(“Pages”)中,因此DataGrid的内容被设置到dvwPages,即sSitePageDataset(“Pages”)。DefaultView.BindDataGrid方法在每次页面加载的时候被调用。

'************************************************************

'

' BindDataGrid 方法

'

' sSite.PageDataset 用来给dataset设置值

'

'************************************************************

Private Sub BindDataGrid(ByVal strSortField As String)

Dim dvwPages As DataView

dvwPages = sSite.PageDataset.Tables("Pages").DefaultView

dvwPages.Sort = strSortField

dgrdPages.DataSource = dvwPages

dgrdPages.DataBind()

End Sub

控件可以根据数据域的结构动态创建列。“自动创建”是DataGrid的默认设置,但是你可以通过使用一个叫AutoGenerateColumns的Boolean属性来手动改变这个设置。当你需要控件只显示你在Columns集合中增加的列时,把这个属性设置成False即可;当你需要控件显示数据源要求的那么多列时,把这个属性设置成True(默认)即可。“自动创建”不能使用自定义表头文本,也不支持文本格式化。因此,这里我把它设置成False。你可以使用<asp:datagrid>服务器控件里的<columns>标签来绑定特定的列。

<columns>

<asp:TemplateColumn>

<ItemTemplate>

<%# DisplayTitle(Container.DataItem( "Title" ), _

Container.DataItem( "Path" )) %>

<br>

<%# Container.DataItem( "Description" ) %>

<br>

<span class="Path">

<%# String.Format("{0} - {1}kb", DisplayPath( _

Container.DataItem( "Path" )) , _

Container.DataItem( "Size" ))%>

</span>

<br>

<br>

</ItemTemplate>

</asp:TemplateColumn>

</columns>

DisplayTitle方法和DisplayPath方法用来把自定义信息显示在DataGrid的列中。

'****************************************

'

' DisplayTitle 方法

'

' 显示搜索页的标题

'

'****************************************

Protected Function DisplayTitle(ByVal Title _

As String, ByVal Path As String) As String

Return String.Format("<A href="{1}">{0}</A>", Title, Path)

End Function

'****************************************

'

' DisplayPath 方法

'

' 返回文件路径

'

'****************************************

Protected Function DisplayPath(ByVal Path As String) As String

Return String.Format("{0}{1}/{2}", _

Request.ServerVariables("HTTP_HOST"), _

Request.ApplicationPath, Path)

End Function

分页

与DataList控件不同的是,DataGrid控件支持数据分页显示,即,把数据源的行分别显示在多个页面中。数据源的大小很容易超过实际页面的区域,因此为了维持服务端的可扩展性和使页面对用户有更高的可访问性,你可以每次只显示某些行。为了实现DataGrid控件可分页功能,你可以通过设置控件的Allowpaging属性来告诉它。

分页栏是DataGrid控件提供的一个非常有趣和值得称赞的特性,它可以让用户轻易的从一个页面跳到另外一个页面。分页栏显示在DataGrid控件的下面,它包含了已有页面的链接。当你点击这里的任何一个链接时,控件自动激活PageIndexChanged事件,并且更新相应的页面索引。当页面索引改变的时候dgrdPages_PageIndexChanged将被调用。

'*****************************************************************

'

' dgrdPages_PageIndexChanged 事件

'

' CurrentPageIndex 被赋值为页面索引的值

' 然后datagrid 通过函数 BindDataGrid 被赋值

'

'*****************************************************************

Protected Sub dgrdPages_PageIndexChanged(ByVal s As Object, _

ByVal e As DataGridPageChangedEventArgs) _

Handles dgrdPages.PageIndexChanged

dgrdPages.CurrentPageIndex = e.NewPageIndex

DisplayContent()

End Sub

你可以通过PagerStyle的Mode属性控制分页栏,Mode属性的值从PagerMode中得到。这里我们选择逐条的数字按钮,每个按钮指向一个特定的页面。

<PagerStyle CssClass="GridPager" Mode="NumericPages"></PagerStyle>

排序

DataGrid控件实际上不支持行排序,但是只要数据源具有排序的功能,它就可以提供很好的排序支持。数据源根据用户在DataGrid控件的用户界面中选择的排序表达式返回排好序的记录。通过设置AllowSorting属性为True内置的排序机制就会被触发。

dgrdPages_SortCommand 被调用使DataGrid排序。SortCommand事件处理器通过DataGridSortCommandEventArgs类的SortExpression属性知道排序表达式。在我们的代码中,排序信息是一直存在的,因为它被保存在页面的ViewState集合中。

注:在我的页面中,我已经使表头无效,但是如果表头显示了,你可以通过它来使DataGrid排序。

'*****************************************************************

'

' dgrdAdditionalItems_SortCommand 事件

'

' ViewState( "SortExpression" ) 被赋予

' 排序表达式的值

' 然后datagrid 通过调用函数 BindDataGrid.被赋值

'

'*****************************************************************

Protected Sub dgrdPages_SortCommand(ByVal s As Object, _

ByVal e As DataGridSortCommandEventArgs) _

Handles dgrdPages.SortCommand

ViewState("SortExpression") = e.SortExpression

DisplayContent()

End Sub

Page.vb

Page对象的作用是存储跟网站每个页面相关的数据。

Page类定义了以下属性

Path

存储文件路径

Title

存储HTML里Title标签里的文本

Keywords

存储HTML里meta keywords标签里的文本

Description

存储HTML里meta description标签里的文本

Contents

存储HTML页面里面的文本

Matchcount

存储在HTML里找到的匹配数

'***************************************************

'

' Size 属性

'

' 设置获取文件的大小

'

'***********************************************

Public Property Size() As Decimal

Get

Return m_size

End Get

Set(ByVal Value As Decimal)

m_size = Value

End Set

End Property

'***************************************************

'

' Path 属性

'

' 设置获取文件的路径

'

'***********************************************

Public Property Path() As String

Get

Return m_path

End Get

Set(ByVal Value As String)

m_path = Value

End Set

End Property

'***********************************************

'

' Title 属性

'

'设置获取文件的标题

'

'***********************************************

Public Property Title() As String

Get

Return m_title

End Get

Set(ByVal Value As String)

m_title = Value

End Set

End Property

'***********************************************

'

' Keywords 属性

'

' 设置获取文件中的 Keywords(在Meta 标签中)

'

'***********************************************

Public Property Keywords() As String

Get

Return m_keywords

End Get

Set(ByVal Value As String)

m_keywords = Value

End Set

End Property

'***********************************************

'

' Description 属性

'

'设置获取文件中的description(在meta tags 中)

'

'***********************************************

Public Property Description() As String

Get

Return m_description

End Get

Set(ByVal Value As String)

m_description = Value

End Set

End Property

'***********************************************

'

' Contents 属性

'

'设置获取文件的内容

'

'***********************************************

Public Property Contents() As String

Get

Return m_contents

End Get

Set(ByVal Value As String)

m_contents = Value

End Set

End Property

'***********************************************

'

' MatchCount 属性

'

'设置获取文件的匹配数

'

'***********************************************

Public Property MatchCount() As Integer

Get

Return m_matchcount

End Get

Set(ByVal Value As Integer)

m_matchcount = Value

End Set

End Property

Page类有两个私有函数和两个公有函数,定义如下:

CheckFileInfo方法

这是个公有方法,它检测title、description和content是否存在,如果title的文本为空,则给它赋予默认值”No Title”;如果description的文本为空则要么把content的值给它要么给它赋”There is no description available for this page”。

'*************************************************

'

' CheckFileInfo 方法

'

'子程序,检测文件是否包含

' title 和 decription

'

'*************************************************

Public Sub CheckFileInfo()

'如果页面不包含title则

' 赋予Title变量适当的显示信息

If IsNothing(m_title) Or m_title.Trim().Equals("") Then

m_title = "No Title"

End If

'如果页面不包含title(description)则

'赋予description变量适当的显示信息

If IsNothing(m_description) Or _

m_description.Trim().Equals("") Then

If IsNothing(m_contents) Or _

m_contents.Trim().Equals("") Then

m_description = _

"There is no description available for this page"

Else

If m_contents.Length > 200 Then

m_description = m_contents.Substring(0, 200)

Else

m_description = m_contents

End If

End If

End If

End Sub

Search方法

Search方法是一个公有方法,它根据搜索条件决定调用SearchPhrase方法还是调用SearchWords。SearchPhrase方法搜索词组而SearchWords搜索所有或任何单词。这两个方法都调用SearchPattern方法,这个方法使用正则表达式来搜索文件。

'*******************************************

'

' Search 方法

'

' 搜索文件子程序

'

'*******************************************

Public Sub Search(ByVal strSearchWords As String, _

ByVal SrchCriteria As SearchCriteria)

'如果用户选择搜索词组

If SrchCriteria = SearchCriteria.Phrase Then

SearchPhrase(strSearchWords)

'如果是搜索所有或任何单词

Else

SearchWords(strSearchWords, SrchCriteria)

End If

End Sub

'******************************************************

'

' SearchPhrase 方法

'

' 搜索文件子程序

'

'******************************************************

Private Sub SearchPhrase(ByVal strSearchWords As String)

Dim mtches As MatchCollection

mtches = SearchPattern(strSearchWords)

'检查词组是否被找到

If mtches.Count > 0 Then

'获取词组被找到的次数

m_matchcount = mtches.Count

End If

End Sub

'**************************************************

'

' SearchWords 方法

'

' 搜索文件子程序

'

'**************************************************

Private Sub SearchWords(ByVal strSearchWords As String, _

ByVal SrchCriteria As SearchCriteria)

Dim intSearchLoopCounter As Integer

Dim sarySearchWord As String()

'包含被搜索的所有单词的数组

Dim mtches As MatchCollection

'分开每个被搜索的单词并放到一个数组中

sarySearchWord = Split(Trim(strSearchWords), " ")

'循环搜索每个要被搜索的单词

For intSearchLoopCounter = 0 To UBound(sarySearchWord)

'设置搜索的方式

mtches = SearchPattern(sarySearchWord(_

intSearchLoopCounter))

If SrchCriteria = SearchCriteria.AnyWords Then

m_matchcount = m_matchcount + mtches.Count

ElseIf SrchCriteria = SearchCriteria.AllWords Then

'检查是否有单词不搜索到

If mtches.Count > 0 Then

'获取搜索单词匹配的次数

If m_matchcount = 0 Or (m_matchcount > 0 _

And m_matchcount > mtches.Count) Then

m_matchcount = mtches.Count

End If

Else

'如果被搜索的单词没有找到,则设置

'搜索被找到变量为false,因为

'其中的一个单词没有被找到

m_matchcount = 0

Exit Sub

End If

End If

Next

End Sub

转义符/b是一个特殊的情况。在正则表达式中,除了在字符“[”和“]”之间表示退格符,/b表示一个单词的边界(在/w和/W之间)。在替换模式中,/b总是表示退格。

当我们不是使用UTF-8编码的时候必须把单词边界去掉。

'****************************************************

'

' SearchPattern 方法

'

' 搜索文件子程序

'

'****************************************************

Private Function SearchPattern( _

ByVal strSearchWord As String) As MatchCollection

Dim regexp As Regex

Dim strPattern

'Set the pattern to search for

regexp = New Regex("", RegexOptions.IgnoreCase)

'Search the file for the phrase

If Searchs.Site.Encoding.Equals("utf-8") Then

strPattern = "/b{0}/b"

Else

strPattern = "{0}"

End If

Return regexp.Matches(m_contents, String.Format(strPattern, _

strSearchWord), RegexOptions.IgnoreCase)

End Function

UserSearch.vb

它包含以下属性:

SearchCriteria

保存、获取用户搜索选项

SearchWords

保存、获取用户搜索的单词

TotalFilesSearched

获取搜索到的总文件数

TotalFilesFound

获取找到的总文件数

'**********************************************************

'

' SearchCriteria 属性

'

' 设置、获取网站搜索条件    '

'**********************************************************

Public Property SearchCriteria() As Searchs.SearchCriteria

Get

Return m_searchCriteria

End Get

Set(ByVal Value As Searchs.SearchCriteria)

m_searchCriteria = Value

End Set

End Property

'**********************************************************

'

' SearchWords 属性

'

'设置、获取网站搜索单词

'

'**********************************************************

Public Property SearchWords() As String

Get

Return m_searchWords

End Get

Set(ByVal Value As String)

m_searchWords = Value

End Set

End Property

'**********************************************************

'

' TotalFilesSearched 属性

'

'获取搜索到的总文件数

'

'**********************************************************

Public ReadOnly Property TotalFilesSearched() As Integer

Get

Return m_totalFilesSearched

End Get

End Property

'**********************************************************

'

' TotalFilesFound 属性

'

' 获取网站文件总数

'

'**********************************************************

Public ReadOnly Property TotalFilesFound() As Integer

Get

Return m_totalFilesFound

End Get

End Property

'**********************************************************

'

' PageDataset 共享属性

'

' 获取整个网站的数据

'

'**********************************************************

Public ReadOnly Property PageDataset() As DataSet

Get

Return m_dstPages

End Get

End Property

Search方法

搜索的实际处理从这里开始。存储搜索结果的DataSet在此创建,ProcessDirectory方法被调用。

'********************************************

'

' Search 方法

'

' 搜索整个网站

'

'********************************************

Public Function Search(ByVal targetDirectory As String) As DataSet

'如果网站是英文的则调用 Server.HtmlEncode 方法

If Searchs.Site.EnglishLanguage = True Then

'在同一个字符串中用HTML编码代替所有的HTML标签

' (停止用户输入HTML标签)

m_searchWords = m_page.Server.HtmlEncode(m_searchWords)

'如果网站不是英文的,则改变脚本标签

Else

'用“<”和“>”的HTML标签替换标签“<”和“>”

m_searchWords = Replace(m_searchWords, "<", "<", 1, -1, 1)

m_searchWords = Replace(m_searchWords, ">", ">", 1, -1, 1)

End If

If m_dstPages Is Nothing Then

m_dstPages = Searchs.PagesDataset.Create()

End If

ProcessDirectory(targetDirectory)

Return m_dstPages

End Function

ProcessDirectory方法

ProcessDirectory方法遍历所有文件并调用ProcessFile方法。然后,变量搜有子目录并调用自己。

'*********************************************

'

' ProcessDirectory 方法

'

' 搜索目录中的文件

'

'********************************************

Private Sub ProcessDirectory(ByVal targetDirectory As String)

Dim fileEntries As String()

Dim subdirectoryEntries As String()

Dim filePath As String

Dim subdirectory As String

fileEntries = Directory.GetFiles(targetDirectory)

' 处理目录中找到的文件列表

For Each filePath In fileEntries

m_totalFilesSearched += 1

ProcessFile(filePath)

Next filePath

subdirectoryEntries = Directory.GetDirectories(targetDirectory)

' 递规进入目录的子目录

For Each subdirectory In subdirectoryEntries

'检测确认要被搜索的文件夹不是被禁用的文件夹

'如果是则不搜索

If Not InStr(1, Searchs.Site.BarredFolders, _

Path.GetFileName(subdirectory), vbTextCompare) > 0 Then

'调用搜索子程序搜索网站

ProcessDirectory(subdirectory)

End If

Next subdirectory

End Sub 'ProcessDirectory

ProcessFile方法

ProcessFile调用GetInfo,GetInfo函数返回包含特定文件所有信息的Searchs.Page对象。然后,它检测matchcount是否大于0并调用CheckFileInfo函数清理保存在Page对象中的信息,然后把文件保存在PagesDataset中。

'*******************************************************

'

' ProcessFile 函数

'

' 处理已找到的文件真实过程在此开始

'

'*******************************************************

Private Sub ProcessFile(ByVal FPath As String)

Dim srchFile As Searchs.Page

srchFile = GetInfo(FPath)

If Not IsNothing(srchFile) Then

srchFile.Search(m_searchWords, m_searchCriteria)

If srchFile.MatchCount > 0 Then

m_totalFilesFound += 1

'Response.Write(srchFile.Contents)

srchFile.CheckFileInfo()

Searchs.PagesDataset.StoreFile(m_dstPages, srchFile)

End If

End If

End Sub 'ProcessFile

GetInfo方法

GetInfo方法的主要任务是获取文件的数据。它调用共享(静态)函数Searchs.FileContent.GetFileInfo大多数的工作在此完成。

'*****************************************************************

'

' GetInfo 方法

'

' 文件信息在此方法被获取

'

'*****************************************************************

Private Function GetInfo(ByVal FPath As String) As Searchs.Page

Dim fileInform As New FileInfo(FPath)

Dim sr As StreamReader

Dim srchFile As New Searchs.Page()

Dim strBldFile As New StringBuilder()

Dim strFileURL As String '保存网站中文件路径

'检测文件扩展名,确认文件

'是要被搜索的后缀的文件

If InStr(1, Searchs.Site.FilesTypesToSearch, _

fileInform.Extension, vbTextCompare) > 0 Then

'm_page.Trace.Warn("File ext.", fileInform.Extension)

'确认要被搜索的文件不是被禁止的文件

'如果是,则不搜索

If Not InStr(1, Searchs.Site.BarredFiles, _

Path.GetFileName(FPath), vbTextCompare) > 0 Then

'm_page.Trace.Warn("File", FPath)

If Not File.Exists(FPath) Then

'm_page.Trace.Warn("Error", _

'String.Format("{0} does not exist.", FPath))

'在此增加抛出异常

'

'

Return Nothing

End If

Searchs.FileContent.GetFileInfo(FPath, srchFile)

Return srchFile

End If

End If

Return Nothing

End Function

FileContent.vb

这里页面中的大量数据被检索出来。如果文件是静态文件,则文件内容通过使用GetStaticFileContent方法被读取出来;如果文件是动态的,则文件内容通过使用GetDynamicFileContent从服务器检索出来。title的信息从title标签中检索出来,meta标签中的descritpion和keywords通过调用GetMetaContent方法检索出来。通过调用Searchs.CleanHtml.Clean方法文件内容从HTML页面中被抽取出来。

'**********************************************

'

' GetFileInfo 方法

'

' 文件信息在此方法中获取

'

'**********************************************

Public Shared Sub GetFileInfo(ByVal FPath As String, _

ByVal srchFile As Searchs.Page)

Dim fileInform As New FileInfo(FPath)

Dim strBldFile As New StringBuilder()

Dim fileSize As Decimal = fileInform.Length / 1024

srchFile.Size = fileSize

GetFilePath(FPath, srchFile)

If InStr(1, Searchs.Site.DynamicFilesTypesToSearch, _

fileInform.Extension, vbTextCompare) > 0 Then

m_page.Trace.Warn("Path", String.Format("{0}/{1}", "", _

srchFile.Path))

GetDynamicFileContent(srchFile)

Else

GetStaticFileContent(FPath, srchFile)

End If

If Not srchFile.Contents.Equals("") Then

srchFile.Contents = sr.ReadToEnd()

'读取文件中title之间的内容

srchFile.Title = GetMetaContent(srchFile.Contents,_

"<title>", "</title>")

'm_page.Trace.Warn("Page Title", strPageTitle)

'读取文件中meta标签的description

srchFile.Description = GetMetaContent(srchFile.Contents,_

"<meta name=""description"" content=""", ",""">")

'm_page.Trace.Warn("Page Desc", strPageDescription)

'读取文件中meta标签的keywords

srchFile.Keywords = GetMetaContent(srchFile.Contents,_

"<meta name=""keywords"" content=""", ",""">")

'm_page.Trace.Warn("Page Keywords", strPageKeywords)

srchFile.Contents = _

Searchs.CleanHtml.Clean(srchFile.Contents)

srchFile.Contents = _

strBldFile.AppendFormat("{0} {1} {2} {3}", _

srchFile.Contents, srchFile.Description, _

srchFile.Keywords, srchFile.Title).ToString.Trim()

'm_page.Trace.Warn("File Info", strBldFile.ToString)

End If

End Sub

'******************************************************

'

' GetStaticFileContent 方法

'

' 文件内容在此方法中被获取

'

'*******************************************************

Private Shared Sub GetStaticFileContent(_

ByVal FPath As String, ByVal srchFile As Searchs.Page)

Dim sr As StreamReader

If Searchs.Site.Encoding.Equals("utf-8") Then

sr = File.OpenText(FPath)

Else

sr = New StreamReader(FPath, _

Encoding.GetEncoding(Searchs.Site.Encoding))

End If

Try

srchFile.Contents = sr.ReadToEnd()

sr.Close()

Catch ex As Exception

m_page.Trace.Warn("Error", ex.Message)

srchFile.Contents = ex.Message

End Try

End Sub

GetDynamicFileContent

GetDynamicFileContent根据编码调用两个分支函数GetDynamicFileContentOther或GetDynamicFileContentUTF总的一个。

'*********************************************************************

'

' GetDynamicFileContent Method

'

' 在此方法中文件内容被获取

'

'*********************************************************************

Private Shared Sub GetDynamicFileContent(ByVal srchFile As Searchs.Page)

Dim wcMicrosoft As System.Net.WebClient

If Searchs.Site.Encoding.Equals("utf-8") Then

GetDynamicFileContentUTF(srchFile)

Else

GetDynamicFileContentOther(srchFile)

End If

End Sub

System.Net.WebClient提供公共方法根据指定的URI资源发送或接收数据。我们使用DownloadData来从资源那里下载数据并返回字节数组。

应用程序使用encoding把原始的编码方式(Unicode)映射为其他编码方式来实现公共语言运行时;使用decoding把非原始编码方式(非Unicode)映射为原始编码方式。System.Text命名空间提供了类允许你对字符进行编码和解码。

'****************************************************************

'

' GetDynamicFileContentOther 方法

'

' 按照提供的编码方式,文件内容在此方法中被获取

'

'

'****************************************************************

Private Shared Sub GetDynamicFileContentOther( _

ByVal srchFile As Searchs.Page)

Dim wcMicrosoft As System.Net.WebClient

Dim fileEncoding As System.Text.Encoding

Try

fileEncoding = System.Text.Encoding.GetEncoding(_

Searchs.Site.Encoding)

srchFile.Contents = fileEncoding.GetString( _

wcMicrosoft.DownloadData(String.Format("{0}/{1}", _

Searchs.Site.ApplicationPath, srchFile.Path)))

Catch ex As System.Net.WebException

m_page.Trace.Warn("Error", ex.Message)

srchFile.Contents = ex.Message

Catch ex As System.Exception

m_page.Trace.Warn("Error", ex.Message)

srchFile.Contents = ex.Message

End Try

End Sub

UTF8Encoding类使用通用字符集转换格式——8位格式(UTF-8)对Unicode字符进行编码。这种编码支持所有Unicode字符值和代理字符。

'*********************************************************************

'

' GetDynamicFileContentUTF 方法

'

' 根据utf-8编码方式文件内容被获取

'

'*********************************************************************

Private Shared Sub GetDynamicFileContentUTF( _

ByVal srchFile As Searchs.Page)

Dim wcMicrosoft As System.Net.WebClient

Dim objUTF8Encoding As UTF8Encoding

Try

wcMicrosoft = New System.Net.WebClient()

objUTF8Encoding = New UTF8Encoding()

srchFile.Contents = objUTF8Encoding.GetString( _

wcMicrosoft.DownloadData(String.Format("{0}/{1}", _

Searchs.Site.ApplicationPath, srchFile.Path)))

Catch ex As System.Net.WebException

m_page.Trace.Warn("Error", ex.Message)

srchFile.Contents = ex.Message

Catch ex As System.Exception

m_page.Trace.Warn("Error", ex.Message)

srchFile.Contents = ex.Message

End Try

End Sub

GetFilePath方法

GetFilePath方法把本地文件夹路径转换成网站的URL。

'*****************************************

'

' GetFilePath 方法

'

' 在此方法中文件路径被转换成用于显示的超链接

'

'

'*****************************************

Private Shared Sub GetFilePath(ByVal strFileURL As String,_

ByVal srchFile As Searchs.Page)

'把服务器文件路径转换成URL文件路径

strFileURL = Replace(strFileURL, m_page.Server.MapPath("./"), "")

'把文件URL中,NT使用的反斜杠替换成

'互联网使用的斜杠

strFileURL = Replace(strFileURL, "/", "/")

'把文件名和路径编码成URL的编码方法

strFileURL = m_page.Server.UrlEncode(strFileURL)

'为了防止编码后出现反斜杠(斜杠)

strFileURL = Replace(strFileURL.Trim(), _

"% 2f", "/", vbTextCompare)

srchFile.Path = strFileURL

m_page.Trace.Warn("Url", srchFile.Path)

End Sub

GetMetaContent方法

GetMetaContent方法使用正则表达式剔除标签并获取需要的信息。

'************************************************

'

' GetMetaContent 方法

'

' Meta的内容在此函数中被剥离

'

'************************************************

Private Shared Function GetMetaContent(ByVal strFile As String, _

ByVal strMetaStart As String, ByVal strMetaEnd As String) As String

'列出在title标签之间的文本

Dim regexp As Regex

Dim strMeta As String

Dim strPattern As String

Dim strInPattern As String

'如果在meta标签中 description 或 keywords 没有找到 ,则

'使用http-equiv= 代替 name=

If InStr(1, LCase(strFile), strMetaStart, 1) = 0 _

And InStr(strMetaStart, "name=") Then

'把 name= 替换成 http-equiv=

strMetaStart = Replace(strMetaStart, "name=", "http-equiv=")

End If

'建立模式

strInPattern = "((.|/n)*?)"

strPattern = String.Format("{0}{1}{2}", _

strMetaStart, strInPattern, strMetaEnd)

regexp = New Regex(strPattern, RegexOptions.IgnoreCase)

'匹配模式

strMeta = regexp.Match(strFile).ToString

'建立模式

strInPattern = "(.*?)"

strPattern = String.Format("{0}{1}{2}", _

strMetaStart, strInPattern, strMetaEnd)

'获取模式内容

strMeta = regexp.Replace(strMeta, strPattern,_

"$1", RegexOptions.IgnoreCase)

Return strMeta

End Function

PagesDataset.vb

这个类用来创建DataSet,它有两个方法组成Create和StoreFile。Create方法创建存储搜索结果的DataSet,StoreFile负责把记录添加到DataSet的DataTable中。

'*******************************************************

'

' Create 方法 – 共享(静态)方法

'

' 为页面创建dataset并返回结果

'

'********************************************************

Public Shared Function Create() As DataSet

'对象被定义

Dim pgDataSet As New DataSet()

Dim keys(1) As DataColumn

'表被创建并加入Table集合

pgDataSet.Tables.Add(New DataTable("Pages"))

'表的结构被定义

pgDataSet.Tables("Pages").Columns.Add("PageId", _

System.Type.GetType("System.Int32"))

pgDataSet.Tables("Pages").Columns.Add("Title",_

System.Type.GetType("System.String"))

pgDataSet.Tables("Pages").Columns.Add("Description", _

System.Type.GetType("System.String"))

pgDataSet.Tables("Pages").Columns.Add("Path", _

System.Type.GetType("System.String"))

pgDataSet.Tables("Pages").Columns.Add("MatchCount", _

System.Type.GetType("System.Int32"))

pgDataSet.Tables("Pages").Columns.Add("Size", _

System.Type.GetType("System.Decimal"))

'PageId 被定义为标识

pgDataSet.Tables("Pages").Columns("PageID").AutoIncrement = True

pgDataSet.Tables("Pages").Columns("PageID").AutoIncrementSeed = 1

'PageId 被定义为主键

keys(0) = pgDataSet.Tables("Pages").Columns("PageId")

pgDataSet.Tables("Pages").PrimaryKey = keys

Return pgDataSet

End Function

'********************************************************

'

' StoreFile 方法 – 共享(静态)方法

'

'为页面创建dataset并返回结果

'

'********************************************************

Public Shared Sub StoreFile(ByVal dstPgs As DataSet,_

ByVal srchPg As Searchs.Page)

'对象被定义

Dim pageRow As DataRow

'新行被创建

pageRow = dstPgs.Tables("Pages").NewRow()

'数据被设置

pageRow("Title") = srchPg.Title

pageRow("Description") = srchPg.Description

pageRow("Path") = srchPg.Path

pageRow("MatchCount") = srchPg.MatchCount

pageRow("Size") = srchPg.Size

'行被加入dataset

dstPgs.Tables("Pages").Rows.Add(pageRow)

End Sub

CleanHtml.vb

CleanHtml类包含单独一个共享(静态)函数,这个函数使用正则表达式清空HTML内容。

'*****************************************************

'

' CleanFileContent 方法

'

' 清空html文件内容的子程序

'

'*****************************************************

Public Shared Function Clean(ByVal Contents As String) As String

Dim regexp As Regex

Dim strPattern As String

strPattern = ""

regexp = New Regex(strPattern, RegexOptions.IgnoreCase)

Contents = regexp.Replace(Contents, _

"<(select|option|script|style|title)(.*?)" & _

">((.|/n)*?)</(SELECT|OPTION|SCRIPT|STYLE|TITLE)>",_

" ", RegexOptions.IgnoreCase)

Contents = regexp.Replace(Contents, "&(nbsp|quot|copy);", "")

'Contents = regexp.Replace(Contents, "<[^>]*>", "")

Contents = regexp.Replace(Contents, "<([/s/S])+?>",_

" ", RegexOptions.IgnoreCase).Replace(" ", " ")

'Contents = regexp.Replace(Contents, "<[^<>]+>",_

" ", RegexOptions.IgnoreCase)

'Contents = regexp.Replace("(<(/w+)[^>]*?>(.*?)<//1>", "$1")

Contents = regexp.Replace(Contents, "/W", " ")

'Trace.Warn("File Contents", Contents)

Return Contents

End Function

Site.vb

Site类由保存整个网站配置信息的共享(静态)属性组成。这些属性使用ConfigurationSettings.AppSettings从web.config文件获取值。

以下是Site类的属性:

FilesTypesToSearch

返回要搜索的文件类型

DynamicFilesTypesToSearch

返回要搜索的动态文件

BarredFolders

返回禁止的文件夹

EnglishLanguage

返回一个Boolean值,表示语言是否为英语

Encoding

返回网站编码

BarredFiles

返回禁止的文件

ApplicationPath

设置或返回应用程序路径

'*************************************************

'

' FilesTypesToSearch 只读属性

'

' 获取网站中要搜索的文件类型

'

'*************************************************

Public Shared ReadOnly Property FilesTypesToSearch() As String

Get

Return ConfigurationSettings.AppSettings(

"FilesTypesToSearch")

End Get

End Property

'*************************************************

'

' DynamicFilesTypesToSearch 只读属性

'

' 获取网站中要搜索的动态文件

'

'*************************************************

Public Shared ReadOnly Property DynamicFilesTypesToSearch() As String

Get

Return ConfigurationSettings.AppSettings(_

"DynamicFilesTypesToSearch")

End Get

End Property

'*************************************************

'

' BarredFolders 只读属性

'

' 获取网站中禁止的文件夹

'

'*************************************************

Public Shared ReadOnly Property BarredFolders() As String

Get

Return ConfigurationSettings.AppSettings("BarredFolders")

End Get

End Property

'*************************************************

'

' BarredFiles 只读属性

'

' 获取网站中禁止的文件

'

'*************************************************

Public Shared ReadOnly Property BarredFiles() As String

Get

Return ConfigurationSettings.AppSettings("BarredFiles")

End Get

End Property

'*************************************************

'

' EnglishLanguage 属性

'

' 获取语言是否为英语

'

'*************************************************

Public Shared ReadOnly Property EnglishLanguage() As String

Get

Return ConfigurationSettings.AppSettings("EnglishLanguage")

End Get

End Property

'*********************************************************************

'

' Encoding 属性

'

' 获取网站的编码

'

'*********************************************************************

Public Shared ReadOnly Property Encoding() As String

Get

Return ConfigurationSettings.AppSettings("Encoding")

End Get

End Property

'**********************************************************

'

' ApplicationPath 属性

'

' 设置或获取应用程序路径

'

'**********************************************************

Public Property ApplicationPath() As String

Get

Return m_ApplicationPath

End Get

Set(ByVal Value As String)

m_ApplicationPath = Value

End Set

End Property

Web.Config

ASP.NET配置系统建立一个可扩展的基本机构,允许你在你的ASP.NET应用程序部署的时候定义配置设置,因此你可以在任何时候增加或修改配置设置,这使对Web应用程序和服务器的操作影响降到最小。多个以Web.Config命名的配置文件可以出现在一个ASP.NET Web应用程序服务器的多个文件夹里面。每个Web.Config文件应用配置设置到它所在的文件夹和它所在的子文件夹。正如前面所述,网站的配置可以设置在web.config文件中。

<appSettings>

<!—在下面行中放置你要搜索的文件类型的名称,以逗号分隔 -->

<add key="FilesTypesToSearch" value=".htm,.html,.asp,.shtml,.aspx" />

<!--在下面行中放置你要搜索的动态文件类型的名称,以逗号分隔-->

<add key="DynamicFilesTypesToSearch" value=".asp,.shtml,.aspx" />

<!--在下面行中放置你不要搜索的文件夹名称,以逗号分隔-->

<add key="BarredFolders"

value="aspnet_client,_private,_vti_cnf,_vti_log,_vti_pvt,

_vti_script,_vti_txt,cgi_bin,_bin,bin,_notes,images,scripts"

/>

<!--在下面行中放置你不要搜索的文件名称(包括文件扩展名),以逗号分隔-->

<add key="BarredFiles"

value="localstart.asp,iisstart.asp,AssemblyInfo.vb,

Global.asax,Global.asax.vb,SiteSearch.aspx"

/>

<!—如果你的网站语言不是英语的,把这个boolean值设置为False-->

<add key="EnglishLanguage" value="True" />

<!—把这个值设置成网站编码-->

<add key="Encoding" value="utf-8" />

</appSettings>

如何整合

应用程序已经通过根目录中的web窗体页面SiteSearch.aspx测试,所以我的建议是你使用同样的方式测试。然后,你可以尝试把它移到任何(网站)子目录。我的所有类已经放到components文件夹,你可以把它放到你的任何文件夹。

注意:

1.对于那些没有Visual Studio.Net的用户

1.从超链接“下载最新版本的示例工程(Visual Studio .NET 非必须的)”下载

2.把SearchDotnet.dll放在根目录的bin文件夹里

3.把SiteSearch.aspx和web.config放在根目录

2.使用XML版本

1.从超链接“下载读写XML的示例工程 (VB.NET) ”

2.项目包含以下文件:

a.AdminiSearch.aspx用来把xml写入文件。

b.SiteSearch.aspx用来搜索文件。

c.我的所有类已经放入components文件夹。

错误

当应用程序被放到根目录的时候,你可能会得到以下错误。“The remote server returned an error: (401) Unauthorized.”或者“The remote server returned an error: (500) Internal Server Error.”

造成这个错误的原因是:

1.如果服务器返回“(401) Unauthorized”,应用程序由于访问权限不能读取文件。

2.如果服务器返回“(500) Internal Server Error”,正在尝试读取的页面返回一个错误,应用程序正在尝试读取的页面因为出现一个错误或者需要参数而返回错误。

按照以下步骤修改错误

1.在web.config中确认BarredFolders列表包含“aspnet_client,_private,_vti_cnf, _vti_log,_vti_pvt,_vti_script,_vti_txt, cgi_bin,_bin,bin,_notes,images,scripts”

2.确认BarredFiles列表是否全面,并且包含“localstart.asp,iisstart.asp”

全球化

搜索引擎模块可以轻易被全球化。以此为目的,我们来看看怎样把它转换成汉语语言。

Web.config

XML声明必须出现在文档任何内容(包括空格),在“<”开始之前的第一行。

在文档中XML声明由以下组成“<?xml version="1.0" encoding="Your Encoding" ?>”,默认情况下,visual studio使用utf-8编码,这需要改变成你要使用的编码。这里我们把它改成gb2312。因此XML声明需要被修改成以下所示:

英语

<?xml version="1.0" encoding="utf-8" ?>

汉语

<?xml version="1.0" encoding="gb2312" ?>

requestEncoding和responseEncoding指定请求和响应的可能编码。Machine.config在.NETFramework安装的时候创建,包含在Machine.config文件的<globalization>标签中默认编码是UTF-8。如果编码没有在Manchine.config或Web.config文件指定,编码默认按照电脑的区域选项的本地设置来指定。我们需要更改requestEncoding和responseEncoding来反映编码的改变。

英语

<globalization requestEncoding="utf-8" responseEncoding="utf-8" />

汉语

<globalization requestEncoding="gb2312" responseEncoding="gb2312" />

为了避免当编码改变的时候生成代码,我们需要在appsettings增加encoding设置。

<!—把网站的编码设置在这里-->

<add key="Encoding" value="gb2312" />

并把EnglishLanguage键设为False。

<!—如果你的网站语言不是英语的,把这个boolean值设置为False-->

<add key="EnglishLanguage" value="False" />

SiteSearch.aspx

最后同样重要的是,codepage属性必须增加在页面的指令中。

英语

<%@ Page Language="vb" Trace="False" AutoEventWireup="false" Codebehind="SiteSearch.aspx.vb" Inherits="SearchDotnet.SiteSearch" debug="false" %>

汉语

<%@ Page Language="vb" Trace="False" AutoEventWireup="false" Codebehind="SiteSearch.aspx.vb" Inherits="SearchDotnet.SiteSearch" debug="false" codePage="936" %>

强化代码

此应用程序是为小型站点编写的,对于更大的站点,代码可以进一步加强。事实上你可能需要周期性地写入到数据库(比如XML文件),然后从那里读取。我将为此提供一些提示。(我已经包含进一个“读写XML示例工程”)

(1)在我的代码中,我使用正则表达式来搜索并过滤数据,不然你将要通过以下方法把全部数据(非过滤的数据)写入XML文件。

Private Shared Sub WriteXmlToFile(ByVal thisDataSet As DataSet)

If thisDataSet Is Nothing Then

Return

End If

thisDataSet.WriteXml(XMLFile)

End Sub

(2)然后你将需要读取xml文件并保存到dataset ,Searchs.Site.PageDataset.Tables("Pages").中

Private Shared Function ReadXmlFromFile() As DataSet

' 创建 DataSet.

Dim newDataSet As New DataSet("New DataSet")

' 读取后台 XML 文档

' 创建读取文件的文件流.

Dim fsReadXml As New System.IO.FileStream(XMLFile,

System.IO.FileMode.Open)

' 创建一个 XmlTextReader 来读取文件.

Dim myXmlReader As New System.Xml.XmlTextReader(fsReadXml)

' 把XML文档读入DataSet.

newDataSet.ReadXml(myXmlReader)

' 关闭 XmlTextReader

myXmlReader.Close()

Return newDataSet

End Function

(3)每次搜索,你将要使用PageDataset.Tables的Select方法来筛选搜索结果,筛选dataset正是如此。FillDataset方法包含创建添加搜索结果(DataRow数组)到数据库的逻辑。

Private Sub FiterPagesDatset()

Dim strExpr As String

Dim foundRows As DataRow()

Dim Field() As String = {

"Title", "Description", "Keywords", "Contents"}

strExpr = SomeFunction '你的建立查询的功能.

foundRows = Searchs.Site.PageDataset.Tables(

"Pages").Select(strExpr)

FillDataset(foundRows)

End Sub

(4)筛选的结果被保存在另外一个dataset中,并用他来显示结果。

有趣的地方

当我在做这个项目的时候,我的问题是怎样显示结果。DataGrid是我的选择,因为我们可以开发出很多其他列表控件所没有的特性。一旦我的问题得到解决,下一步就是怎样传递内容到DataGrid,DataSet是唯一可选的。在保存信息到DataSet之前,当我进一步处理时,我不得不把页面的大量信息移来移去。我决定使用Site对象来保存信息。

作者之一建议下面的最优方法:

a.类应该要小到大约只有几个方法和属性。

b.方法应该短小到大约只有几行。

经过仔细的分析代码和保持最优方法在心里,我重新设计代码成现在的样子。

历史

l         修改代码可以读取动态页面。

l         增强代码支持全球化。

l         我已经加入一个读写XML的示例工程

许可

本文没有附加明确的许可,但是在文章正文或者下载文件中可能包含使用条款,如果有疑问请通过下面讨论区和作者联系。

可能使用的许可作者列表可以在这里找到。

关于作者

Stevan Rodrigues

Stevan 是微软认证.NET架构解决方案开发专家(早期MCSD.Net获得者 – 世界范围内前2500之一), 微软认证.NET应用程序开发专家 – MCAD.Net (特许会员 – 世界范围内前5000名的开发工程师之一).
他是理科硕士,主修数学,在阿拉伯联合酋长国的Dubai从事IT业已经有一段时间。最近他在印度作为一名技术架构师。

职业:

架构师

地点:

印度

其他有名的应用程序和工具文章:

  • ToDoList 5.6.3 - A simple but effective way to keep on top of your tasks

A hierarchical task manager with native XML support for custom reporting.

  • Visual Leak Detector - Enhanced Memory Leak Detection for Visual C++

A memory leak detector for Visual C++ packaged in an easy to use library!

  • KeePass Password Safe

KeePass is a free, open-source, light-weight and easy-to-use password safe.

  • VC++7 to VC++6 project converter

This tool automatically converts Visual C++ 7.0 projects back to Visual C++ 6.0 projects.

  • Super ImageList and ToolBar generator

A drag & drop ImageList and ToolBar generator . Simplifies creation of large image lists and supports effects .

站内搜索引擎(ASP.NET)相关推荐

  1. 站内搜索引擎初探:haystack全文检索,whoosh搜索引擎,jieba中文分词

    在做django项目当中,不免要使用到站内搜索引擎,网站呈现的内容除了列表,详细页,首页之外,用户也需要通过搜索引擎来找到自己需要的内容. 安装: pip install django-haystac ...

  2. 加入一个基于GOOGLE的站内搜索引擎

    由于这一次的客户只能提供虚拟主机作为项目运行平台,无法搭配中文分词组件,原来自行开发的站内搜索引擎无法发挥最大的功效(主要是不能自动分析关键词,只能通过指定相关索引字段,以及手工输入TAG的机制来生成 ...

  3. 站内搜索引擎之比较〔转〕

    有很多网站都在网页上加个"站内搜索引擎"."搜索引擎"."全文检索"等等相关字样. 用户一用,结果发现,既不能多关键组合查询,也不能支持国际 ...

  4. 王通:站内搜索引擎的SEO策略

    越来越多的大中型网站都有了站内搜索引擎,站内搜索引擎如果采用正确的SEO策略,可以产生大量非常合理的关键词页面,可以在各大搜索引擎中带来巨大的流量.站内搜索引擎该如何SEO呢?很简单,只需要做好以下三 ...

  5. 用C++来设计开发的基于boost文档的站内搜索引擎项目,点赞收藏起来!

    So Easy搜索引擎 项目描述 主要技术 项目特点 0. 准备工作 1. 预处理模块 2. 索引模块 3. 搜索模块 4. 服务器模块 项目难点和提升 结束语 项目描述 boost官网虽然提供了在线 ...

  6. 【项目】 基于BOOST的站内搜索引擎

    目录 1. 简介 建立搜索引擎的宏观体系 技术栈和项目环境 正排索引 and 倒排索引 2. 数据去标签与数据清洗模块 -- Parser 数据去标签 parser.cc parser.cc 的代码结 ...

  7. 如何搭建一个站内搜索引擎(一) 第1章 写在最前

    搜索引擎,对很多人来说,熟悉又陌生.熟悉,是因为每个人每天都能接触到,比如百度.google.淘宝内部搜索:陌生,是因为鲜有人了解他的原理. 因为工作需要,有幸参与负责了一个站内搜索的项目.所以可以从 ...

  8. 基于swiftype应用于Hexo-Yilia-主题的站内搜索引擎

    本文基于Hexo,Yilia主题添加站内搜索功能与使用swiftype实现站内搜索 文章之前首先感谢以上两位作者YeHbeats与 huangjunhui swiftype Swiftype 可以为网 ...

  9. 使用 LayUI+SpringBoot+Solr 模仿百度、做站内搜索引擎

    一.前言 全文检索于 sql 模糊查询,最大的区别,在于 ① 前者能将要查询的关键字符串先进行灵活分词,再进行匹配, ② 后者只会直接死板匹配. ③ 很多网站都有站内搜索,每个后台的应该会,故做了个 ...

  10. 百度 和 谷歌 的站内搜索引擎代码

    网上曾有过两段Google和百度站内搜索的代码,如下(注意:代码中的"网站地址"要去掉http://) <!--Google站内搜索开始--> <form met ...

最新文章

  1. Vs2010 MFC 简单制作过程中的问题
  2. Eclipse 3.7 3.x SWT/Jface 开发环境搭建
  3. linux 没有root登陆
  4. git保留两个repo的commit并进行合并
  5. lucene分布式索引
  6. Kubernetes基础组件概述
  7. docker 学习手冊-中文版下载
  8. 11 个 Git 面试题
  9. ESP8266 wifi钓鱼
  10. C++复习(五)(const、static、inline、引用与指针、new/delete)
  11. Unity3D做的DEMO
  12. Zookeeper+ActiveMQ集群搭建
  13. QQ聊天记录删除了怎么恢复
  14. debugger心得
  15. Ubuntu 20.04.2.0 LTS 下Geany 1.36的“编译文件”和“生成当前文件”两个按键不可用
  16. 《鹰眼》(Eagle Eye):对电子媒介的反恐
  17. Windows 11系统映像恢复到新硬盘的3种方式
  18. 都是反反复复反反复复反反复复
  19. 70.用Dnsmasq构建DNS服务器
  20. SPSS-Friedman 秩和检验-非参数检验-K个相关样本检验 案例解析(转)

热门文章

  1. html定义微调器,bootstrap4 input数值微调插件
  2. 活化脂修饰NOTA,NOTA-NHS ester,CAS:1338231-09-6
  3. 计算机减法函数word,Word中减法公式怎么用
  4. Oracle sysman.mgmt_jobs导致数据库自动重启
  5. 华为云买网站买另外服务器,华为云网站在买其他服务器
  6. Android studio emulator Terminated
  7. 实现单个页面,多个百度分享(动态修改百度分享链接)
  8. RTC风向标:11月最值得关注的26个热点
  9. siri 语义识别_如何查看使用Siri识别的歌曲列表
  10. 用完加速器国内的网址打不开了?