【AI大模型应用开发】【综合实战】AI+搜索,手把手带你实现属于你的AI搜索引擎(附完整代码)

  • 大家好,我是同学小张,日常分享AI知识和实战案例
  • 欢迎 点赞 + 关注 👏,持续学习持续干货输出
  • +v: jasper_8017 一起交流💬,一起进步💪。
  • 微信公众号也可搜【同学小张】 🙏

本站文章一览:

在这里插入图片描述


现在市面上有很多的AI+搜索的应用或插件,一直想学习其背后的实现原理。今天咱们就学习一下,并且亲自动手实践,从0开始,搭建一个自己的AI搜索引擎。最终实现效果如下:

在这里插入图片描述
话不多说,开干。

本文代码参考:https://mp.weixin.qq.com/s/6F22Mls7zYJw5xJE-d6GrA,在原代码基础上进行了修改,适配了OpenAI 的API。

0. 框架

先来搞定框架。

代码中,服务端使用了Python + Flask框架,前端使用HTML。通过 Flask的render_template函数渲染HTML页面。render_template 函数是 Flask 提供的一个工具,用于渲染 Jinja2 模板。Jinja2 是一个 Python 的模板引擎,它允许你在 HTML 文件中使用 Python 变量和表达式。

代码如下:

from flask import Flask, render_template, request, jsonify
@app.route('/', methods=['GET'])
def index():
    chat_history = history
    return render_template('ai_search.html', history=chat_history)

代码中,HTML页面的名称为 “ai_search.html”。

注意,在使用此种方法渲染HTML页面时,需要将HTML文件放到templates文件夹下,否则找不到文件,报错。

在这里插入图片描述
也就是说,工程目录结构应该如下:

在这里插入图片描述

1. 服务端(Python + Flask)

服务端就是利用Flask封装一个个地接口,然后进行相应处理。

1.1 Search接口

@app.route('/search', methods=['GET', 'POST'])
def search():
    if request.method == 'POST':
        keyword = request.form['keyword']
    elif request.method == 'GET':
        keyword = request.args.get('keyword', '')
    else:
        keyword = ''
    
    results = crawl_pages(keyword)
    output = ""
    for result in results:
     output += f"<li><a id='myID' href='javascript:void(0);' οnclick='handleLinkClick(\"{result['url']}\")'>{result['title']}</a></li><br>"
    return output

Search接口接收用户输入的关键字,然后调用 crawl_pages 接口去获取检索结果。

1.1.1 crawl_pages接口

def crawl_pages(query_text, page_num=2):
    browser = mechanicalsoup.Browser()
    query_text_encoded = quote(query_text) # 关键字编码,例如关键字中的中文要转码才能作为URL的参数
    results = []
    for page_index in range(1, page_num+1):
        url = f"https://search.cctv.com/search.php?qtext={query_text_encoded}&type=web&page={page_index}"
        page = browser.get(url)
        soup = BeautifulSoup(page.text, 'html.parser')
        web_content_links = soup.find_all('a', id=lambda x: x and x.startswith('web_content_'))
        for i, link in enumerate(web_content_links):
            target_page = parse_qs(urlparse(link['href']).query).get('targetpage', [None])[0]
            results.append({'title': link.text, 'url': target_page})
    return results

该接口通过关键字来去固定网页去检索该关键字,获取前两页的检索结果,通过前两页的检索结果,通过爬虫,将结果的标题和URL提取出来。

(1)url = f"https://search.cctv.com/search.php?qtext={query_text_encoded}&type=web&page={page_index}",这是表明去哪个网页搜索这个关键字。这个链接相当于以下操作,去CCTV网搜关键字:

在这里插入图片描述
(2)通过简单的爬虫,将以上获取到的检索结果界面中的所有结果的URL和标题提取出来:target_page = parse_qs(urlparse(link['href']).query).get('targetpage', [None])[0],例如这一句,提取URL。

(3)然后你就会获得一堆的URL,返回给Search接口后,通过 output += f"<li><a id='myID' href='javascript:void(0);' onclick='handleLinkClick(\"{result['url']}\")'>{result['title']}</a></li><br>" 组装结果,插入到HTML中去显示。也就是侧边栏的效果:

在这里插入图片描述

1.2 generate-text接口

@app.route('/generate-text', methods=['POST'])
def generate_text_api():
    prompt = request.json['prompt']
    result = generate_text(prompt)
    return jsonify(result)

该接口是将用户输入的关键字当作Prompt,给大模型,让大模型根据这个信息回复点什么东西。中间没有什么特别的处理。要说值得注意的,就是 history.append({"user": prompt, "bot": generated_text}) 来将对话信息添加到历史记录里面。

def get_openai_chat_completion(messages, temperature, model = "gpt-3.5-turbo-1106"):
    response = client.chat.completions.create(
        model = model,
        messages = messages,
        temperature = temperature,
    )
    return response

def generate_text(prompt, temperature=0.5):
    messages = [
        {
            "role": "user",
            "content": prompt,
        }   
    ]
    response = get_openai_chat_completion(messages = messages, temperature=temperature)
    generated_text = response.choices[0].message.content
    history.append({"user": prompt, "bot": generated_text})  # 将用户输入和模型输出添加到历史记录中
    return {"status": "success", "response": generated_text}

这一步的效果如下,与检索毫无关系:

在这里插入图片描述

1.3 page_content接口

该接口是通过URL来获取网页内容。就是一个简单的爬虫程序,将网页中的文字和图片提取出来。

@app.route('/page_content')
def page_content():
    url = request.args.get('url', '')
    if not url:
        return '缺少 url 参数'
    browser = mechanicalsoup.Browser()
    page = browser.get(url)
    page.encoding = 'utf-8'  # 指定页面的编码为 utf-8
    soup = BeautifulSoup(page.text, 'html.parser')
    all_text = ''
    all_images = []

    # 获取页面中所有文本内容
    for element in soup.find_all(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span']):
        all_text += element.get_text() + ' '

    # 获取页面中所有图片链接
    for img in soup.find_all('img'):
        img_src = img.get('src')
        if img_src:
            all_images.append("https:"+img_src)

    return f"文本内容: {all_text}<br>图片链接: {', '.join(all_images)}"

2. 前端(HTML)

2.1 用户输入关键字后的动作

先来看下前端HTML代码中,当用户点击提交按钮后的动作,重点是下面几行。

inputForm.addEventListener('submit', async (event) => {
    ......

    const aa = document.getElementById('listView');
    aa.innerHTML = await getA(userInput);
    const response = await generateText(userInput);
    hideTypingAnimation(userMessage);
    
    ......
});

可以看到,当用户点击提交按钮后,首先调用了 getA 函数:

async function getA(prompt) {
    const response = await fetch(SERVER_URL + `/search?keyword=${prompt}`, {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json'
        }
    });
    return await response.text();
}

getA函数,调用了服务端的 Search接口,去固定网页检索关键字,获取URL和标题列表。

然后,紧接着调用了 generateText 函数:

async function generateText(prompt) {
    const response = await fetch(SERVER_URL + '/generate-text', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            prompt
        })
    });
    return await response.json();
}

generateText 函数,调用了服务端的 generate-text 函数,利用大模型进行回复。

2.2 用户点击侧边栏标题后的动作

当用户点击侧边栏的某个标题后,执行的动作如下:

async function handleLinkClick(link) {
    const content = await getPageContent(link);
    
    ......
    
    const response = await generateText("总结内容:" + content);
    
    ......
}

首先,调用了 getPageContent 接口,通过服务端的 page_content 接口,爬取了该URL中的所有文字内容和图片内容。

然后,通过 generateText 接口,调用服务端的 generate-text 接口,使用大模型对这些文字内容进行总结,从而形成下面的效果:

在这里插入图片描述

3. 完整代码

3.1 ai_search.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chat with AI</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            height: 100vh;
            margin: 0;
            font-family: Arial, sans-serif;
        }

        .website-container {
            position: fixed;
            top: 0;
            right: 0;
            width: 350px;
            height: 100%;
            border: 1px solid #ccc;
            overflow-y: auto;
            background-color: #f9f9f9;
            padding: 10px;
        }

        .chat-container {
            height: 100%;
            width: 85%;
            overflow: hidden;
            overflow-y: auto;
            padding: 10px;
            margin-right: 220px;
            /* 腾出右侧栏的宽度 */
        }

        .chat-container::-webkit-scrollbar {
            display: none;
        }

        .avatar-user {
            width: 40px;
            height: 40px;
            background-color: #7fb8e7;
            /* 设置用户头像颜色 */
            border-radius: 50%;
            /* 将头像设置为圆形 */
            margin-left: 10px;
            /* 调整头像与消息之间的间距 */
        }

        .avatar-bot {
            width: 40px;
            height: 40px;
            right: 0;
            background-color: #28a745;
            /* 设置机器人头像颜色 */
            border-radius: 50%;
            /* 将头像设置为圆形 */
            margin-right: 10px;
            /* 调整头像与消息之间的间距 */
            object-fit: cover;
            /* 防止头像变形 */
        }

        .message {
            display: flex;
            align-items: center;
            /* 垂直居中消息和头像 */
            margin-bottom: 1rem;
        }


        .message-text {
            padding: 10px;
            word-wrap: break-word;
            border-radius: 6px;
            max-width: 70%;
            margin:100px;
        }

        .message-text-user {
            padding: 10px;
            border-radius: 6px;
            max-width: 70%;
            margin:100px;
            word-wrap: break-word;
            background-color: #ececec;
        }

        .user-message {
            display: flex;
            justify-content: flex-end;

        }

        .bot-message .message-text {
            background-color: #2ea44f;
            color: white;
        }

        .input-container {
            position: fixed;
            bottom: 0;
            left: 0;
            width: calc(100% - 220px);
            /* 考虑右侧栏的宽度 */
            display: flex;
            align-items: center;
            background-color: #f9f9f9;
            padding: 10px;
        }

        .input-field {
            flex-grow: 1;
            padding: 0.75rem;
            border: 1px solid #d1d5da;
            border-radius: 6px;
            margin-right: 1rem;
        }

        .send-button {
            padding: 0.75rem 1rem;
            background-color: #2ea44f;
            color: white;
            border: none;
            border-radius: 6px;
            cursor: pointer;
        }

        .del-button {
            padding: 0.75rem 1rem;
            background-color: #aeaeae;
            color: white;
            border: none;
            margin-right: 10px;
            border-radius: 6px;
            cursor: pointer;
        }

        .send-button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .typing-indicator {
            position: absolute;
            margin-bottom: 50px font-size: 0.8rem;
            color: #586069;
        }

        .typing:before,
        .typing:after {
            content: '';
            display: inline-block;
            width: 0.75rem;
            height: 0.75rem;
            border-radius: 50%;
            margin-right: 0.25rem;
            animation: typing 1s infinite;
        }

        @keyframes typing {
            0% {
                transform: scale(0);
            }

            50% {
                transform: scale(1);
            }

            100% {
                transform: scale(0);
            }
        }

        /* 样式定义 */
        .listView {
            list-style-type: none;
            margin: 0;
            padding: 0;
        }

        .listView li {
            background-color: #f4f4f4;
            padding: 10px;
            margin-bottom: 5px;
            box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
            transition: box-shadow 0.3s ease;
        }

        .listView li:hover {
            box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2);
        }

        .listView li a {
            text-decoration: none;
            color: #333;
            display: block;
            transition: color 0.3s ease;
        }

        .listView li a:hover {
            color: #ff6600;
        }
    </style>
</head>

<body style="display: flex; flex-direction: column; height: 100vh;">

    <div id="website-container" class="website-container">
        <ul class="listView" id="listView"></ul>
    </div>
    <div style="height: 90%; width:80%; overflow-y: auto; display: flex; flex-direction: column;">
        <ul class="chat-container" id="chat-container">
            {% for item in history %}
                {% if loop.index == 1 %}
                    <!-- 对于第一条消息,可能想要做一些特殊处理 -->
                    <li class="message user-message">
                        <div class="message-text-user">{{ item.user }}</div> <!-- 这里应该插入用户消息 -->
                        <div class="avatar-user"></div>
                    </li>
                    <li class="message bot-message">
                        <div class="avatar-bot"></div>
                        <div class="message-text">{{ item.bot }}</div> <!-- 这里应该插入机器人消息 -->
                    </li>
                {% else %}
                    <!-- 对于其他消息,正常处理 -->
                    <li class="message user-message">
                        <div class="message-text-user">{{ item.user }}</div>
                        <div class="avatar-user"></div>
                    </li>
                    <li class="message bot-message">
                        <div class="avatar-bot"></div>
                        <div class="message-text">{{ item.bot }}</div>
                    </li>
                {% endif %}
            {% endfor %}
        </ul>
    </div>

    <form class="input-container" id="input-form" method="POST"
        style="position: fixed; bottom: 0; left: 0; width: 65%;">
        <button type="button" class="del-button" id="del-button" style="width: 100px;" onclick='del()'>清除</button>
        <input type="text" placeholder="你负责搜,我负责找" class="input-field" id="input-field" name="prompt" autocomplete="off"
            style="width: calc(100% - 100px);">
        <button type="submit" class="send-button" id="send-button" disabled style="width: 100px;">搜索</button>
    </form>

    <script>
        const SERVER_URL = '';
        const inputForm = document.getElementById('input-form');
        const inputField = document.getElementById('input-field');
        const chatContainer = document.getElementById('chat-container');

        inputField.addEventListener('input', () => {
            const userInput = inputField.value.trim();
            document.getElementById('send-button').disabled = !userInput;
        });

        inputForm.addEventListener('submit', async (event) => {
            event.preventDefault();
            const userInput = inputField.value.trim();
            const chatContainer = document.getElementById('chat-container');
            if (!userInput) {
                return;
            }
            const userMessage = createMessageElement(userInput, 'user-message', "message-text-user", "avatar-user");
            chatContainer.appendChild(userMessage);
            inputField.value = '';
            chatContainer.scrollTop = chatContainer.scrollHeight;
            inputField.disabled = true;
            document.getElementById('send-button').disabled = true;
            showTypingAnimation(userMessage);

            const aa = document.getElementById('listView');
            aa.innerHTML = await getA(userInput);
            const response = await generateText(userInput);
            hideTypingAnimation(userMessage);
            if (response.status === 'success') {
                const botResponse = createMessageElement(response.response, 'bot-message', "message-text", "avatar-bot");
                chatContainer.appendChild(botResponse);
                printMessageText(botResponse);

            } else {
                alert(response.message);
            }
            inputField.disabled = false;
            inputField.focus();
        });

        async function generateText(prompt) {
            const response = await fetch(SERVER_URL + '/generate-text', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    prompt
                })
            });
            return await response.json();
        }
        async function getA(prompt) {
            const response = await fetch(SERVER_URL + `/search?keyword=${prompt}`, {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json'
                }
            });
            return await response.text();
        }
        function createMessageElement(text, className, name, bot) {
            const message = document.createElement('li');
            message.classList.add('message', className, 'typing');
            if (bot == "avatar-bot") {
                message.innerHTML = `
                <div class=${bot}></div>
                <div class=${name}>${text}</div>
                `;
            } else {
                message.innerHTML = `
                <div class=${name}>${text}</div>
                <div class=${bot}></div>
                
                `;
            }
            return message;
        }

        function showTypingAnimation(element) {
            const chatContainer = document.getElementById('chat-container');
            chatContainer.scrollTop = chatContainer.scrollHeight + 10;
            const rect = element.getBoundingClientRect();
            const topPosition = rect.top + window.scrollY + rect.height;
            const leftPosition = rect.left + window.scrollX;
            const typingIndicator = document.createElement('div');
            typingIndicator.classList.add('typing-indicator');
            typingIndicator.style.top = `${topPosition}px`;
            typingIndicator.style.left = `${leftPosition}px`;
            typingIndicator.innerHTML = '思考中...';

            document.body.appendChild(typingIndicator);
        }

        function hideTypingAnimation(element) {
            const typingIndicator = document.querySelector('.typing-indicator');
            if (typingIndicator) {
                typingIndicator.remove();
            }
            element.classList.remove('typing');
        }

        // 添加逐字打印效果
        function printMessageText(message) {
            const chatContainer = document.getElementById('chat-container');
            const text = message.querySelector('.message-text');
            const textContent = text.textContent;
            text.textContent = '';
            for (let i = 0; i < textContent.length; i++) {
                setTimeout(() => {
                    text.textContent += textContent.charAt(i);
                    chatContainer.scrollTop = chatContainer.scrollHeight;
                }, i * 10); // 控制打印速度
            }
        }
        async function handleLinkClick(link) {
            const content = await getPageContent(link);
            console.log(link);
            console.log(content);
            const userMessage = createMessageElement("总结中:" + link, 'user-message', "message-text-user", "avatar-user");
            showTypingAnimation(userMessage);

            const chatContainer = document.getElementById('chat-container');
            chatContainer.appendChild(userMessage);
            const response = await generateText("总结内容:" + content);
            hideTypingAnimation(userMessage);
            if (response.status === 'success') {
                const botResponse = createMessageElement(response.response, 'bot-message', "message-text", "avatar-bot");
                chatContainer.appendChild(botResponse);
                printMessageText(botResponse);

            } else {
                alert(response.message);
            }
        }
        function del(url) {
            const response = fetch(SERVER_URL + `/clear`, {
                method: 'POST'
            });
            location.replace("/");

            return 0;
        }
        // 获取页面内容
        async function getPageContent(url) {
            const response = await fetch(SERVER_URL + `/page_content?url=${url}`, {
                method: 'GET'
            });
            return await response.text();
        }
    </script>
</body>

</html>

3.2 ai_search.py

from flask import Flask, render_template, request, jsonify
from http import HTTPStatus
from openai import OpenAI
import mechanicalsoup
from bs4 import BeautifulSoup
from flask_cors import CORS
from urllib.parse import urlparse, parse_qs, quote
app = Flask(__name__)
client = OpenAI()

CORS(app)

history = []
def crawl_pages(query_text, page_num=2):
    browser = mechanicalsoup.Browser()
    query_text_encoded = quote(query_text)
    results = []
    for page_index in range(1, page_num+1):
        url = f"https://search.cctv.com/search.php?qtext={query_text_encoded}&type=web&page={page_index}"
        page = browser.get(url)
        soup = BeautifulSoup(page.text, 'html.parser')
        web_content_links = soup.find_all('a', id=lambda x: x and x.startswith('web_content_'))
        for i, link in enumerate(web_content_links):
            target_page = parse_qs(urlparse(link['href']).query).get('targetpage', [None])[0]
            results.append({'title': link.text, 'url': target_page})
    return results

def get_openai_chat_completion(messages, temperature, model = "gpt-3.5-turbo-1106"):
    response = client.chat.completions.create(
        model = model,
        messages = messages,
        temperature = temperature,
    )
    return response

def generate_text(prompt, temperature=0.5):
    messages = [
        {
            "role": "user",
            "content": prompt,
        }   
    ]
    response = get_openai_chat_completion(messages = messages, temperature=temperature)
    generated_text = response.choices[0].message.content
    history.append({"user": prompt, "bot": generated_text})  # 将用户输入和模型输出添加到历史记录中
    return {"status": "success", "response": generated_text}

@app.route('/', methods=['GET'])
def index():
    chat_history = history
    return render_template('ai_search.html', history=chat_history)

@app.route('/generate-text', methods=['POST'])
def generate_text_api():
    prompt = request.json['prompt']
    result = generate_text(prompt)
    return jsonify(result)

@app.route('/clear', methods=['POST'])
def clear():
    global history
    history = []
    return '', HTTPStatus.NO_CONTENT

@app.route('/search', methods=['GET', 'POST'])
def search():
    if request.method == 'POST':
        keyword = request.form['keyword']
    elif request.method == 'GET':
        keyword = request.args.get('keyword', '')
    else:
        keyword = ''
    
    results = crawl_pages(keyword)
    output = ""
    for result in results:
     output += f"<li><a id='myID' href='javascript:void(0);' οnclick='handleLinkClick(\"{result['url']}\")'>{result['title']}</a></li><br>"
    return output

@app.route('/page_content')
def page_content():
    url = request.args.get('url', '')
    if not url:
        return '缺少 url 参数'
    browser = mechanicalsoup.Browser()
    page = browser.get(url)
    page.encoding = 'utf-8'  # 指定页面的编码为 utf-8
    soup = BeautifulSoup(page.text, 'html.parser')
    all_text = ''
    all_images = []

    # 获取页面中所有文本内容
    for element in soup.find_all(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span']):
        all_text += element.get_text() + ' '

    # 获取页面中所有图片链接
    for img in soup.find_all('img'):
        img_src = img.get('src')
        if img_src:
            all_images.append("https:"+img_src)

    return f"文本内容: {all_text}<br>图片链接: {', '.join(all_images)}"

if __name__ == '__main__':
    app.run(debug=True)

3.3 运行

运行 ai_search.py,打开提示中链接。

在这里插入图片描述

3.4 可能需要安装的依赖

pip install Flask -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install mechanicalsoup -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install Jinja2

3.5 一定是通过Jinja2加载HTML,而不是直接打开HTML

直接打开HTML文件会显示异常:

在这里插入图片描述

4. 总结

本文我们从0开始写了一个AI+搜索的搜索引擎。整体原理还是比较简单的,搜索的原理就是固定URL+关键字,然后爬取网页内的标题和URL,就算是结果了。至于文本总结就更不用多说了,前面的文章详细介绍和实践过。

这个例子很简单,但应该算比较完整了,可以作为后续类似项目的快速开始,在此基础上快速搭建出自己的原型产品。

大家可以上手运行一下,然后运行过程中,你会对这个例子产生一些改进的想法。

有改进的想法,可以一起交流~

如果觉得本文对你有帮助,麻烦点个赞和关注呗 ~~~


  • 大家好,我是 同学小张,日常分享AI知识和实战案例
  • 欢迎 点赞 + 关注 👏,持续学习持续干货输出
  • +v: jasper_8017 一起交流💬,一起进步💪。
  • 微信公众号也可搜同学小张 🙏

本站文章一览:

在这里插入图片描述

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
E桶金行业搜索引擎系统(包含多线程客户端蜘蛛系统) V1.6 版发布! E桶金行业搜索引擎 特别适用于超大、中型信息门户、行业门户、电子商务等网站使用。 它是一款真正意义上的搜索引擎:具有自己的蜘蛛、分词、索引、搜索等全套功能。 而且所有功能全部基于web页面完成,您只需要购买一款支持asp.net的虚拟主机就能完成本程序的部署,网站轻松上线。 本程序具有毫秒级高速搜索, 搜索结果相关度排序 。多关键词搜索、超长词条搜索、关键词高亮显示。 该程序为ASP.NET2.0版本程序,只要空间支持asp.net2.0即可。 需要确保iis的默认文档中包含default.aspx 演示地址:http://so.12ym.com 官方网址:http://www.12ym.com/3/111/ 技术支持:http://bbs.12ym.com/ 后台管理地址:/admin/default.aspx 默认帐号和密码均为:etongjin 本程序包中的Spider.rar文件是客户端蜘蛛插件,用于多线程快速索引网站,并抓取快照。 本程序包中的MsSql.rar文件为MsSql数据库版本加文件包,如果您想使用sql版本,参照mssql增值包中的说明。 注意:本程序的商业授权分两种版本:Access版本和MsSql版本,如果您的授权是Access版本,那么升级为MsSql版本后,将变为MsSql免费版本,如果想升级为MsSql商业版本,请联系E桶金客服。 本系统目前只支持网站根目录浏览,不能放到虚拟目录或者子文件夹中! 如果您想购买E桶金行业搜索引擎,可以联系销售客服QQ。 销售客服QQ:83498254,178301967 E桶金软件(http://www.etongjin.com),助您博得人生的第一桶金 ! 2011.06.01升级(1.6版本)的主要内容如下: 1.提供两种蜘蛛客户端索引和网站索引进行合并的策略 2.优化编码识别规则,大幅件减少搜索日志乱码现象 3.后台可批量删除某一域名下的所有搜引文件的功能! 4.可过滤某一ip的搜索记录,避免数据库迅速膨胀 5.将广告内容的字数限制由100个字符增长到128个字符 6.升级优化客户端蜘蛛的部分功能:修正入口地址设置中屏蔽的url关键词设置后无效的问题;修正定时更新,间隔更新设置后,按钮无法提交的问题;蜘蛛程序每执行一阶段采集任务后,自动释放cpu和内存,避免蜘蛛一直执行会挂死。 2011.05.18升级(1.51版本) 1.5版升级的主要内容如下: 1.全新规划系统架构,彻底分离数据访问层,推出Access和MS SQL两个版本。(非常重要) 2.增加百宝箱功能,可以像百度开放平台一样轻松地在自己的搜索中增加自己特有的应用,如:万年历、时间、在线汇率等; 3.推广用户增加保存公司名称和网址的功能。(重要) 4.优化前台页面显示。 2011.02.18升级(1.1版本) 1.1版升级的主要内容如下: 1.推广中心集成支付宝支付功能,可以直接在线充值投放竞价广告。(非常重要) 2.增加记录百度、Google等搜索引擎爬行记录的功能,并在搜索日志和广告点击记录中过滤蜘蛛的爬行日志。 3.后台的“广告点击记录”、“用户贡献列表”、“搜索日志列表”、“蜘蛛爬行列表”均增加“删除全部记录”的按钮,当数据库较大时可选择一次性清理这些数据。(重要) 4.对推广中心和后台管理界面的细节和样式进行优化。(重要) 2011.01.12升级(1.0 Beta版本) 1.0版升级的主要内容如下: 1.增加客户端蜘蛛功能,多线程抓取快照,建立索引,更加高效、稳定。(重要) 2.初步完成插件机制,为以后的程序功能扩展提供基础。(重要) 3.对搜索列表页面进行SEO处理,避免百度、Google等搜索引擎陷入链接陷阱。 2010.12.17升级(0.95版本) 0.95版升级的主要内容如下: 1.提高系统稳定性:优化蜘蛛抓取网页时索引建立的方式,避免因服务器异常,导致整站索引损坏的问题;优化一些蜘蛛抓取的容错功能。(重要) 2.完善搜索关键词竞价广告系统,使广告匹配更精准;增加竞价价格查询;并修正关键词广告删除后,个别时候仍会扣掉广告主一些积分的bug。(重要) 3.完善索引系统:增加对页面meta标签中description属性的索引;修正个别页面会索引css或js代码的问题;修正后台有时无法删除索引的问题。 4.增加一些后台配置功能:自由设置当本站搜索不出结果时是否自动补充百度搜索结果;自由设置网站蜘蛛的名称;自由设置注册的推广用户是否需要审核。(重要) 2010.09.10升级(0.92版本) 0.92版升级的主要内容如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

同学小张

如果觉得有帮助,欢迎给我鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值