当前位置: 首页 > news >正文

android网站开发大良营销网站建设好么

android网站开发,大良营销网站建设好么,文案写作软件app,广州公司注册代理机构零 项目背景/原理/技术栈 1.介绍boost准标准库 2.项目实现效果 3.搜索引擎宏观架构图 这是一个基于Web的搜索服务架构 客户端-服务器模型#xff1a;采用了经典的客户端-服务器模型#xff0c;用户通过客户端与服务器交互#xff0c;有助于集中管理和分散计算。简单的用户… 零 项目背景/原理/技术栈 1.介绍boost准标准库 2.项目实现效果 3.搜索引擎宏观架构图 这是一个基于Web的搜索服务架构 客户端-服务器模型采用了经典的客户端-服务器模型用户通过客户端与服务器交互有助于集中管理和分散计算。简单的用户界面客户端似乎很简洁用户通过简单的HTTP请求与服务端交互易于用户操作。搜索引擎功能服务器端的搜索器能够接收查询请求从数据存储中检索信息这是Web搜索服务的核心功能。数据存储有专门的存储系统用于存放数据文件如HTML文件有助于维护数据的完整性和持久性。模块分离搜索器、存储和处理请求的模块被分开这有助于各模块独立更新和维护. 4.搜索过程的原理~正排,倒排索引 5.技术栈和项目环境,工具 技术栈:C/C C11 STL boost准标准库 JsonCPP cppjieba cpp-httplib  html css js jQuery Ajax 项目环境:Centos7  华为云服务器 gcc/g/makefile Vscode 一 Paser数据清洗,获取数据源模块 const std::string src_path data/input/; const std::string output_file data/output/dest.txt; class DocInfo { public:std::string _title;std::string _content;std::string _url; }; Paser模块主逻辑  int main() {std::vectorstd::string files_list;// 第一步 把搜索范围src_path内的所有html的路径文件名放到 files_list中if (!EnumFileName(src_path, files_list)){lg(_Error,%s,enum filename err!);exit(EnumFileNameErr);}// 第二步 将files_list中的文件打开,读取并解析为DocInfo后放到 web_documents中std::vectorDocInfo html_documents;if (!ParseHtml(files_list, html_documents)){lg(_Error,%s,parse html err!);exit(ParseHtmlErr);}// 第三步 将web_documents的信息写入到 output_file文件中, 以\3为每个文档的分隔符if (!SaveHtml(html_documents, output_file)){lg(_Error,%s,save html err!);exit(SaveHtmlErr);} } 枚举文件从给定的源路径src_path中枚举所有HTML文件并将它们的路径和文件名放入files_list中。 解析HTML读取files_list中的每个文件解析它们为DocInfo对象可能包含标题、URL、正文等元素然后存储到html_documents向量中。 保存文档将html_documents中的文档信息写入到指定的输出文件output_file中文档之间用\3ASCII码中的End-of-Text字符分隔。 EnumFileName bool EnumFileName(const std::string src_path, std::vectorstd::string *files_list) {namespace fs boost::filesystem;fs::path root_path(src_path);if (!fs::exists(root_path)) // 判断路径是否存在{lg(_Fatal,%s%s,src_path.c_str(), is not exist);return false;}// 定义一个空迭代器,用来判断递归是否结束fs::recursive_directory_iterator end;// 递归式遍历文件for (fs::recursive_directory_iterator it(src_path); it ! end; it){if (!fs::is_regular(*it))continue; // 保证是普通文件if (it-path().extension() ! .html)continue; // 保证是.html文件files_list-push_back(it-path().string()); // 插入的都是合法 路径.html文件名}return true; } ParseHtml bool ParseHtml(const std::vectorstd::string files_list, std::vectorDocInfo *html_documents) {for (const std::string html_file_path : files_list){// 第一步 遍历files_list,根据路径文件名,读取html文件内容std::string html_file;if (!ns_util::FileUtil::ReadFile(html_file_path, html_file)){lg(_Error,%s,ReadFile err!);continue;}DocInfo doc_info;// 第二步 解析html文件,提取titleif (!ParseTitle(html_file, doc_info._title)){lg(_Error,%s%s,ParseTitle err! ,html_file_path.c_str());continue;}// 第三步 解析html文件,提取content(去标签)if (!ParseContent(html_file, doc_info._content)){lg(_Error,%s,ParseContent err!);continue;}// 第四步 解析html文件,构建urlif (!ParseUrl(html_file_path, doc_info._url)){lg(_Error,%s,ParseUrl err!);continue;}// 解析html文件完毕,结果都保存到了doc_info中// ShowDcoinfo(doc_info);html_documents-push_back(std::move(doc_info)); // 尾插会拷贝,效率不高,使用move}lg(_Info,%s,ParseHtml success!);return true; } 1.ReadFile class FileUtil{public:static bool ReadFile(const std::string file_path, std::string *out){std::ifstream in(file_path, std::ios::in); // 以输入方式打开文件if (!in.is_open()){lg(_Fatal,%s%s%s,ReadFile:,file_path.c_str(), open err!);return false;}std::string line;while (std::getline(in, line)){*out line;}in.close();return true;}}; 2.ParseTitle static bool ParseTitle(const std::string html_file, std::string *title) {size_t left html_file.find(title);if (left std::string::npos)return false;size_t right html_file.find(/title);if (right std::string::npos)return false;int begin left std::string(title).size();int end right;// 截取[begin,end-1]内的子串就是标题内容if (end-begin0){lg(_Error,%s%s%s,ParseTitle:,output_file.c_str(),has no title);return false;}std::string str html_file.substr(begin, end - begin);*title str;return true; } 3.ParseContent static bool ParseContent(const std::string html_file, std::string *content) {// 利用简单状态机完成去标签工作enum Status{Lable,Content};Status status Lable;for (char ch : html_file){switch (status){case Lable:if (ch )status Content;break;case Content:if (ch )status Lable;else{// 不保留html文本中自带的\n,防止后续发生冲突if (ch \n)ch ;content-push_back(ch);}break;default:break;}}return true; } 4.ParseUrl static bool ParseUrl(const std::string html_file_path, std::string *url) {std::string url_head https://www.boost.org/doc/libs/1_84_0/doc/html;std::string url_tail html_file_path.substr(src_path.size());*url url_head / url_tail;return true; }SaveHtml doc_info内部用\3分隔,doc_info之间用\n分隔 //doc_info内部用\3分隔,doc_info之间用\n分隔 bool SaveHtml(const std::vectorDocInfo html_documents, const std::string output_file) {const char sep \3;std::ofstream out(output_file, std::ios::out | std::ios::binary|std::ios::trunc);if (!out.is_open()){lg(_Fatal,%s%s%s,SaveHtml:,output_file.c_str(), open err!);return false;}for(auto doc_info:html_documents){std::string outstr;outstr doc_info._title;outstr sep;outstr doc_info._content;outstr sep;outstr doc_info._url;outstr\n;out.write(outstr.c_str(),outstr.size());}out.close();lg(_Info,%s,SaveHtml success!);return true; } 二 Index建立索引模块 索引的相关结构 class DocInfo // 解析后的html文档的相关信息{public:std::string _title;std::string _content;std::string _url;uint64_t _doc_id;};class InvertedElem{public:uint64_t _doc_id;std::string _word;int _weight; // 关键词word在该文档内的权重,方便后续查找时按顺序显示};私有化构造函数和析构函数通过将构造函数和析构函数设为私有禁止了外部通过常规方式创建Index类的实例。 禁用拷贝构造函数和拷贝赋值操作符通过将拷贝构造函数和赋值操作符标记为delete防止了类的拷贝确保了单例的唯一性。 静态实例和互斥锁用静态成员变量instance来存储这个类的唯一实例并使用静态互斥锁_mutex来保证在多线程环境下的线程安全。 GetInstance方法这是一个静态方法用于获取Index类的唯一实例。如果instance为空则实例化一个新的Index对象。这个方法在创建实例之前和之后都有一次判断实例是否为空的逻辑这是“双重检查锁定”模式它可以减少每次调用GetInstance方法时所需的锁定操作从而提高性能。 正向索引和倒排索引的存储结构类中定义了两个私有成员变量来存储正向索引_forward_index和倒排索引_inverted_index。正向索引是一个vector存储文档信息DocInfo对象而倒排索引是一个unordered_map它映射一个字符串关键词到一个InvertedListvectorInvertedElem。 构建索引的方法类提供了两个方法BuildForwardIndex和BuildInvertedIndex分别用于构建正向索引和倒排索引。这两个方法的具体实现在这个代码片段中没有给出。 检索功能的方法BuildIndex方法可能用于建立索引GetForwardIndex和GetInvertedList方法分别用于获取正向索引和倒排索引中的数据。 BuildIndex bool BuildIndex(const std::string input_path) // 构建索引{std::fstream in(input_path, std::ios::in | std::ios::binary);if (!in.is_open()){lg(_Fatal,%s%s%s,BuildIndex fail! ,input_path.c_str(), cannot open);return false;}std::string html_line; // 每个html的的DocInfo以\n间隔int cnt1; //debugwhile (std::getline(in, html_line)){DocInfo *doc_info BuildForwardIndex(html_line);if (doc_info nullptr){lg(_Error,%s%s%s%s,BuildForwardIndex fail! ,who? ,html_line.c_str(), continue next html);continue;}if (!BuildInvertedIndex(*doc_info)){lg(_Error,%s%s%d,BuildInvertedIndex fail! ,id: ,doc_info-_doc_id);continue;}cnt;if(cnt%100 0)std::coutcnt:cntstd::endl; }lg(_Info,%s%d,BuildIndex over cnt:,cnt);in.close();return true;} 字符串切分 class StringUtil{public:static void SplitString(const std::string str, std::vectorstd::string *ret_strs, const std::string sep){boost::split(*ret_strs, str, boost::is_any_of(sep), boost::token_compress_on);}};const char *const DICT_PATH ./dict/jieba.dict.utf8;const char *const HMM_PATH ./dict/hmm_model.utf8;const char *const USER_DICT_PATH ./dict/user.dict.utf8;const char *const IDF_PATH ./dict/idf.utf8;const char *const STOP_WORD_PATH ./dict/stop_words.utf8;class JiebaUtil{public:static void CutString(const std::string src,std::vectorstd::string *ret){_jieba.CutForSearch(src,*ret);}private:static cppjieba::Jieba _jieba;};cppjieba::Jieba JiebaUtil::_jieba(DICT_PATH,HMM_PATH,USER_DICT_PATH,IDF_PATH,STOP_WORD_PATH); 这段代码展示了两个C工具类StringUtil和JiebaUtil它们都包含静态方法用于处理字符串分割和中文分词功能。 StringUtil 类 这个类提供了一个静态方法SplitString它使用Boost库的split函数来将字符串str依据分隔符sep分割并将结果存储在传入的向量ret_strs中。boost::token_compress_on参数指定如果分隔符在字符串中连续出现那么多个分隔符将被视作一个。 JiebaUtil 类 这个类提供了一个静态方法CutString它用于中文的分词。方法接受一个源字符串src和一个用于存储分词结果的向量ret。类包含一个私有静态成员_jieba它是cppjieba::Jieba类的一个实例。cppjieba::Jieba是一个中文分词库的C实现。类在底部使用_jieba成员的静态初始化语法来初始化这个Jieba分词器实例。 常量路径定义 代码中还定义了一些指向分词所需字典文件的路径常量 DICT_PATH指向基础字典文件。HMM_PATH指向用于HMM隐马尔可夫模型的模型文件。USER_DICT_PATH指向用户自定义的词典文件。IDF_PATH指向逆文档频率IDF字典文件。STOP_WORD_PATH指向停用词字典文件。 BuildForwardIndex DocInfo *BuildForwardIndex(const std::string html_line){// 1~ 切分字符串std::vectorstd::string ret_strs;const std::string sep \3;ns_util::StringUtil::SplitString(html_line, ret_strs, sep);if (ret_strs.size() 3)return nullptr;// 2~ 填充doc_infoDocInfo doc_info;doc_info._title ret_strs[0];doc_info._content ret_strs[1];doc_info._url ret_strs[2];doc_info._doc_id _forward_index.size(); // 插入第一个时id size 0// 3~ 插入到正排索引_forward_index_forward_index.push_back(std::move(doc_info));return _forward_index.back();} BuildInvertedIndex bool BuildInvertedIndex(const DocInfo doc_info){struct words_cnt{int title_cnt 0;int content_title 0;};// 1~ 对doc_info的title和content进行分词std::unordered_mapstd::string, words_cnt words_frequency;std::vectorstd::string words_title;//保存title分词后的结果std::vectorstd::string words_content;//保存content分词后的结果ns_util::JiebaUtil::CutString(doc_info._title, words_title);ns_util::JiebaUtil::CutString(doc_info._content, words_content);// 2~ 统计词频填充words_frequencyfor (auto word : words_title)//to_lower转换不能是const修饰{boost::to_lower(word); // 需要统一转化成为小写,因为搜索时不区分大小写//boost::to_lower_copy(word);words_frequency[word].title_cnt;}for (auto word : words_content){boost::to_lower(word); // 需要统一转化成为小写,因为搜索时不区分大小写//boost::to_lower_copy(word);words_frequency[word].content_title;}// 3~ 自定义权重 title:content 10:1static const int title_weight 10;static const int content_weight 1;// 4~ 对words_frequency内的每个关键词创建InvertedElem并填充for (const auto kv : words_frequency){InvertedElem inverted_ele;inverted_ele._doc_id doc_info._doc_id;inverted_ele._word kv.first;inverted_ele._weight title_weight * kv.second.title_cnt content_weight * kv.second.content_title;// 5~ 将该文档的所有InvertedElem分别插入到倒排索引 _inverted_index中InvertedList inverted_list _inverted_index[kv.first];inverted_list.push_back(std::move(inverted_ele));//_inverted_index[kv.first].push_back(std::move(inverted_ele));}return true;} 三 Searcher搜索模块 InitSearcher Search 分词处理 用户输入的查询字符串 query 通过 ns_util::JiebaUtil::CutString 函数进行分词分词结果存储在 key_words 向量中。 搜索和去重 遍历分词后的关键词。对每个关键词都先将其转换为小写以实现大小写不敏感的搜索然后获取对应的倒排索引链InvertedList。如果倒排索引链存在遍历链中的每个元素并在 tokens_map 中以文档ID为键聚合数据合并权重和关键词实现对同一文档的去重。 排序 将 tokens_map 中聚合的结果转移到一个向量 inverted_ele_all 中并根据权重对其进行降序排序这样权重高的更相关的文档会排在前面。 构建JSON结果 遍历排序后的 inverted_ele_all 向量对于每个元素使用它的文档ID去查询正向索引获取文档的详细信息如标题、内容和URL。将这些信息构建成一个JSON对象并添加到一个 Json::Value 类型的 ret 数组中。函数最后使用 Json::FastWriter 将 ret 转换成JSON格式的字符串并存储在 json_str 指针指向的字符串中。 // query是用户输入的搜索关键字// json_str是返回给用户浏览器的搜索结果void Search(const std::string query, std::string *json_str){// 1~对query进行分词std::vectorstd::string key_words;ns_util::JiebaUtil::CutString(query, key_words);std::unordered_mapuint64_t,InvertedElemDedup tokens_map;//去重id后的结果for (auto key_word : key_words){// 查询的关键词全部转换为小写,提取出来的信息不区分大小写boost::to_lower(key_word);// 2~对分词结果 分别进行搜索ns_index::Index::InvertedList *inverted_list _index-GetInvertedList(key_word);if (inverted_list nullptr){continue; // 这个词没能找到 对应的倒排拉链}for(auto elem: *inverted_list){auto dedup_ele tokens_map[elem._doc_id];dedup_ele._doc_id elem._doc_id;dedup_ele._weight elem._weight;dedup_ele._words.push_back(elem._word);}}// 优化点:对所有的ele合并后指向的doc_id进行去重 这里只关心weight和idstd::vectorInvertedElemDedup inverted_ele_all;for(auto kv:tokens_map){inverted_ele_all.push_back(std::move(kv.second));}// 3~对所有的inverted_element按照wegiht排序sort(inverted_ele_all.begin(), inverted_ele_all.end(),[](InvertedElemDedup left,InvertedElemDedup right){return left._weight right._weight;});// 4~序列化,构建json串返回给用户 -- 使用jsoncppJson::Value ret;int cnt 0; // debugfor (auto ele : inverted_ele_all){ns_index::DocInfo *doc_info _index-GetForwardIndex(ele._doc_id);if (doc_info nullptr)continue;Json::Value element;element[title] doc_info-_title;// 搜索时需要摘要,不是所有的content,后面优化element[desc] GetDesc(doc_info-_content, ele._words[0]);element[url] doc_info-_url;// element[weight] ele._weight;// element[word] ele._words[0];// element[id] (int)ele._doc_id; // json自动将int转化为stringret.append(element);}//Json::StyledWriter writer;Json::FastWriter writer;*json_str writer.write(ret);}private:std::string GetDesc(const std::string html_content, const std::string word){// 找到word在content中首次出现的位置,向前截取prev_stepbyte,向后截取next_stepbyte// 向前prev_step则从content开头开始,向后不足next_step则到content结尾// 1~ 找到word首次出现的位置std::cout word std::endl; // debugauto iter std::search(html_content.begin(), html_content.end(), word.begin(), word.end(),[](int l, int r){return std::tolower(l) std::tolower(r);});if (iter html_content.end()){lg(_Error,%s,content里面没找到word);return None1;}// 找到了int pos std::distance(iter, html_content.end());const int prev_step 50;const int next_step 50;// 2~ 确定begin和end位置int begin pos prev_step ? pos - prev_step : 0;int end (pos next_step) html_content.size() ? pos next_step : html_content.size();// 3~ 截取描述子串[begin,end)并返回if (begin end) // end一定大于begin{lg(_Error,%s,begin end 越界了);return None2;}std::string desc html_content.substr(begin, end - begin);desc ...;return desc;}}; 四 http_server模块 const std::string input data/output/dest.txt;//从input里读取数据构建索引 const std::string root_path ./wwwroot; int main() {std::unique_ptrns_searcher::Searcher searcher(new ns_searcher::Searcher());searcher-SearcherInit(input);httplib::Server svr;svr.set_base_dir(root_path.c_str()); // 设置根目录// 重定向到首页svr.Get(/, [](const httplib::Request , httplib::Response rsp){ rsp.set_redirect(/home/LZF/boost_searcher_project/wwwroot/index.html); });svr.Get(/s,[searcher](const httplib::Request req,httplib::Response rsp){if(!req.has_param(word)){rsp.set_content(无搜索关键字!,test/plain,charsetutf-8);return;}std::string json_str;std::string query req.get_param_value(word);std::cout用户正在搜索: querystd::endl;searcher-Search(query,json_str);rsp.set_content(json_str,application/json);});svr.listen(0.0.0.0, 8800); } 初始化 定义了 input 和 root_path 两个字符串常量分别表示索引文件的路径和服务器的根目录。 创建搜索对象 使用 std::unique_ptr 创建了 Searcher 类的一个实例并通过 SearcherInit 方法初始化以从指定的 input 文件中构建索引。 创建和配置服务器 使用 httplib::Server 类创建了一个HTTP服务器实例设置了服务器的根目录为 root_path。 首页重定向 服务器对根路径 / 的GET请求进行处理通过 set_redirect 方法将请求重定向到指定的HTML页面路径。 搜索请求处理 对路径 /s 的GET请求进行处理这是搜索功能的实现部分。服务器检查请求中是否包含名为 word 的参数 如果请求中没有 word 参数则返回错误信息。如果有它将提取 word 参数的值打印出查询的内容并调用 Searcher 实例的 Search 方法来进行搜索。搜索的结果是一个JSON字符串它会设置为响应体的内容。 启动服务器 使用 svr.listen 方法监听 0.0.0.0 上的 8800 端口使服务器开始接受连接和处理请求。 httplib::Server 是 httplib 库中用于创建和管理HTTP服务器的类。 五 前端模块 !DOCTYPE html html langen headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0script srchttp://code.jquery.com/jquery-2.1.1.min.js/scripttitleboost 搜索引擎/titlestyle/* 去掉网页中的所有的默认内外边距html的盒子模型 */* {/* 设置外边距 */margin: 0;/* 设置内边距 */padding: 0;}/* 将我们的body内的内容100%和html的呈现吻合 */html,body {height: 100%;}/* 类选择器.container */.container {/* 设置div的宽度 */width: 800px;/* 通过设置外边距达到居中对齐的目的 */margin: 0px auto;/* 设置外边距的上边距保持元素和网页的上部距离 */margin-top: 15px;}/* 复合选择器选中container 下的 search */.container .search {/* 宽度与父标签保持一致 */width: 100%;/* 高度设置为52px */height: 52px;}/* 先选中input标签 直接设置标签的属性先要选中 input标签选择器*//* input在进行高度设置的时候没有考虑边框的问题 */.container .search input {/* 设置left浮动 */float: left;width: 600px;height: 50px;/* 设置边框属性边框的宽度样式颜色 */border: 1px solid black;/* 去掉input输入框的有边框 */border-right: none;/* 设置内边距默认文字不要和左侧边框紧挨着 */padding-left: 10px;/* 设置input内部的字体的颜色和样式 */color: #CCC;font-size: 14px;}/* 先选中button标签 直接设置标签的属性先要选中 button标签选择器*/.container .search button {/* 设置left浮动 */float: left;width: 150px;height: 52px;/* 设置button的背景颜色#4e6ef2 */background-color: #4e6ef2;/* 设置button中的字体颜色 */color: #FFF;/* 设置字体的大小 */font-size: 19px;font-family:Georgia, Times New Roman, Times, serif;}.container .result {width: 100%;}.container .result .item {margin-top: 15px;}.container .result .item a {/* 设置为块级元素单独站一行 */display: block;/* a标签的下划线去掉 */text-decoration: none;/* 设置a标签中的文字的字体大小 */font-size: 20px;/* 设置字体的颜色 */color: #4e6ef2;}.container .result .item a:hover {text-decoration: underline;}.container .result .item p {margin-top: 5px;font-size: 16px;font-family:Lucida Sans, Lucida Sans Regular, Lucida Grande, Lucida Sans Unicode, Geneva, Verdana, sans-serif;}.container .result .item i{/* 设置为块级元素单独站一行 */display: block;/* 取消斜体风格 */font-style: normal;color: green;}/style /head bodydiv classcontainerdiv classsearchinput typetext value请输入搜索关键字button onclickSearch()搜索一下/button/divdiv classresult/div/divscriptfunction Search(){let query $(.container .search input).val();console.log(query query);$.get(/s, {word: query}, function(data){console.log(data);BuildHtml(data);});}function BuildHtml(data){let result_lable $(.container .result);result_lable.empty();for( let elem of data){let a_lable $(a, {text: elem.title,href: elem.url,target: _blank});let p_lable $(p, {text: elem.desc});let i_lable $(i, {text: elem.url});let div_lable $(div, {class: item});a_lable.appendTo(div_lable);p_lable.appendTo(div_lable);i_lable.appendTo(div_lable);div_lable.appendTo(result_lable);}}/script/body /html HTML结构 搜索栏 (div.search): 包含一个文本输入框用户可以在其中输入搜索关键字。包含一个按钮当点击时会调用 Search() JavaScript函数。 搜索结果显示区域 (div.result): 这是一个空的div将来用来动态显示搜索结果。 样式 通过CSS设置了页面和元素的样式包括输入框、按钮、搜索结果等。 JavaScript功能 Search() 函数: 从输入框中获取用户输入的查询词。使用 jQuery 的 $.get() 函数异步向服务器的 /s 路径发送一个GET请求并将用户的查询词作为参数传递。当收到响应时调用 BuildHtml() 函数处理数据并构建结果HTML。 BuildHtml() 函数: 清空结果显示区域为新的搜索结果做准备。遍历响应数据中的每个搜索结果并为每个结果创建包含标题、描述和URL的HTML元素。将创建的HTML元素附加到结果显示区域。 用户交互 当用户输入查询词并点击搜索按钮时页面将不会进行重新加载而是通过JavaScript异步请求后端服务并将结果动态地插入到页面中。 jQuery 页面通过CDN引用了 jQuery 库以简化DOM操作和Ajax请求。
http://www.sczhlp.com/news/181401/

相关文章:

  • 国外哪些网站做产品推广比较好cmd iis网站
  • 衡水高端网站建设网上购物流程
  • 南宁中小企业网站制作wordpress的博文页面如何自定义
  • 网站建设费与无形资产阿里云智能logo设计网站
  • 禅城做网站头条发布视频成功显示404
  • 注册网站的免费网址是什么东莞网站建设品牌公司
  • 完整网站开发教程有网络但是网页打不开
  • 餐饮企业网站设计wordpress 5.0.1编辑器
  • 网站域名优势广州昨天发生重大新闻
  • 吉林市建设工程档案馆网站吉安网页制作公司
  • 贵阳网站设计与开发怎么做广告营销是做什么的
  • 方特网站是谁做的雅布设计平面
  • 北京网站关键词优化河北邢台封闭最新消息
  • 主机如何做服务器建网站公司要做网站去哪里
  • 长沙网站推广工具营销网站建设教学
  • joomla 网站建设教程网站建设简介是什么
  • 网站开发有什么语言photoshop在线制作
  • 酒店网站的开发及其设计方案农产品网络营销
  • 百讯科技网站建设旅游酒店网站建设
  • 网站备案需要提交什么资料建设网站视频教程
  • 天津做公司网站广州哪个网站建设公司好
  • php做购物网站系统电商网站介绍
  • 网站页面创意php 深圳 电子商务网站开发
  • 网站开发 项目介绍邢台手机网站建设多少钱
  • 珠海做网站费用珠海工商年检到哪个网站做
  • wordpress网站顶部加横幅西安做网站公司那家好
  • 桂林网站开发m0773嵌入式软件开发工程师做什么
  • 自己设计好的网站怎么设置访问建设网站需要注意的事项
  • wordpress core主题wordpress seo
  • 网店装修关键词排名优化技巧