做百科的网站,wordpress ip地址只能访问首页,办网站费用多少钱,网站后台设计教程视频需求设计 实现分析
系统通过访问URL得到html代码#xff0c;通过正则表达式匹配html#xff0c;通过反向引用来得到商品的标题、图片、价格、原价、id#xff0c;这部分逻辑在java中实现。
匹配商品的正则做成可视化编辑#xff0c;因为不同网站的结构不同#xff0c;同…需求设计 实现分析
系统通过访问URL得到html代码通过正则表达式匹配html通过反向引用来得到商品的标题、图片、价格、原价、id这部分逻辑在java中实现。
匹配商品的正则做成可视化编辑因为不同网站的结构不同同一个网站的结构会随时间发生变化为方便修改做成可视化编辑。以九块邮为例分析匹配商品的正则 由此图可见一个正则由多个单元项组成每个单元项都是一个单独的正则包括匹配商品的字段项和字段项前后的标志字符串比如匹配价格的[\d\.]价格前面的html 。最终组合成的正则需要能够正确解析出一个个商品的标题、图片、价格、原价和id字段。
后端代码
匹配代码
package com.learn.reptile.utils;import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.learn.reptile.entity.po.Item;import cn.hutool.http.HttpUtil;public class ItemCraw {/*** 通过url获取html然后解析出出商品* param url* param regexpStr 商品匹配正则表达式* param startStr 开始匹配字符串* param endStr 结束匹配字符串* return*/public static ListItem parseItemsFromUrl(String url, String regexpStr, String startStr, String endStr) {String html HttpUtil.get(url);if(StringUtils.isNotBlank(endStr)) {html html.substring(html.indexOf(startStr), html.lastIndexOf(endStr));} else {html html.substring(html.indexOf(startStr));}ListItem items new ArrayList();Pattern pattern Pattern.compile(regexpStr);Matcher matcher pattern.matcher(html);// 每一个匹配整体while(matcher.find()) {Item item new Item();item.setItemId(matcher.group(id));item.setPic(matcher.group(pic));item.setTitle(matcher.group(title));item.setPrice(Double.parseDouble(matcher.group(price)));item.setPrePrice(Double.parseDouble(matcher.group(prePrice)));items.add(item);}return items;}}匹配结果实体类
package com.learn.reptile.entity.po;import java.util.Date;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;import lombok.Data;Data
public class Item {TableId(type IdType.AUTO)private Long id;// 淘宝商品idprivate String itemId;// 来源匹配网站的编码private String source;private String title;private String pic;private double price;private double prePrice;// 采集时间private Date createTime;
}controller类
package com.learn.reptile.web.controller;import java.util.List;import javax.annotation.Resource;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.learn.reptile.entity.po.Item;
import com.learn.reptile.entity.po.ItemWebsite;
import com.learn.reptile.entity.vo.R;
import com.learn.reptile.utils.ItemCraw;RequestMapping(/item)
RestController
public class ItemController {PostMapping(test)public RListItem test(RequestBody ItemWebsite itemWebsite) {return R.ok(ItemCraw.parseItemsFromUrl(itemWebsite.getUrl(), itemWebsite.getRegexpStr(), itemWebsite.getStartStr(), itemWebsite.getEndStr()));}
}
前端代码
添加router位置src/router/modules/home.js。router的path中增加了参数:id即网站的id。
{path: /item,component: Layout,name: item,meta: {title: 商品,},icon: icon-home,children: [{path: itemWebsite,name: itemWebiste,component: () import(/views/item_website/index.vue),meta: {title: 网站,},},{path: itemRegexp/:id,name: itemRegexp,component: () import(/views/item_website/regexp.vue),meta: {title: 商品匹配正则,},hidden: true,},],},
位置src/views/item_website/regexp.vue
分析
用regexpItems表示正则单元项列表每个regexpItem包含三个字段type 表示匹配商品的某个字段还是仅仅是分隔部分matchType 表示该部分的正则模式matchStr 表示该正则模式需要用到的字符串。
type 数据
key valueid商品idtitle标题pic图片price价格prePrice原价其他
matchType 数据
keyvalueall任意字符串exclude不包含 某些字符串 的字符串fix固定字符串number价格,[\d\.]
正则单元项html: divclassregexp_itemv-for(regexpItem, index) in regexpItems:keyindex{{ index 1 }}el-icon clickregexpItems.splice(index, 1)CloseBold //el-icondiv classlinediv classlabel类型/divdiv classfieldel-selectv-modelregexpItem.typechangechangeType(regexpItem)el-optionv-for(name, code) in types:keycode:valuecode:labelname{{ name }}/el-option/el-select/div/divdiv classlinediv classlabel匹配类型/divdiv classfieldel-radio-group v-modelregexpItem.matchTypeel-radio valuenumber labelnumber数值/el-radioel-radio valueall labelall任意字符/el-radioel-radio valueexclude labelexclude除/el-radioel-inputclassmatch_inputv-ifregexpItem.matchType excludev-modelregexpItem.matchStr/el-radio valuefix labelfix固定/el-radioel-inputv-ifregexpItem.matchType fixv-modelregexpItem.matchStr//el-radio-group/div/div/div
页面整体布局为左中右结构左侧是正则单元项列表中间是操作按钮右边是测试匹配结果完整html部分代码如下
templatediv stylemargin: 10px;{{ itemWebsite.name }}匹配规则/divdiv styledisplay: flex;div stylewidth: 60%div classformdiv classform_label匹配开始字符串/divdiv classform_fieldel-input v-modelitemWebsite.startStr/el-input/divdiv classform_label匹配结束字符串/divdiv classform_fieldel-input v-modelitemWebsite.endStr/el-input/div/divdivclassregexp_itemv-for(regexpItem, index) in regexpItems:keyindex{{ index 1 }}el-icon clickregexpItems.splice(index, 1)CloseBold //el-icondiv classlinediv classlabel类型/divdiv classfieldel-selectv-modelregexpItem.typechangechangeType(regexpItem)el-optionv-for(name, code) in types:keycode:valuecode:labelname{{ name }}/el-option/el-select/div/divdiv classlinediv classlabel匹配类型/divdiv classfieldel-radio-group v-modelregexpItem.matchTypeel-radio valuenumber labelnumber数值/el-radioel-radio valueall labelall任意字符/el-radioel-radio valueexclude labelexclude除/el-radioel-inputclassmatch_inputv-ifregexpItem.matchType excludev-modelregexpItem.matchStr/el-radio valuefix labelfix固定/el-radioel-inputv-ifregexpItem.matchType fixv-modelregexpItem.matchStr//el-radio-group/div/div/div/divdiv stylewidth: 180px; text-align: center;div stylemargin-bottom: 10px;el-button round typeprimary clickadd增加匹配项/el-button/divdiv stylemargin-bottom: 10px;el-button typeprimary round clicksave保存/el-button/divel-button typeprimary round clicktest测试/el-button/divdiv stylewidth: 40%;pre{{ resultItems }}/pre/div/div
/template
javascript部分
import {getCurrentInstance,reactive,toRefs,ref,computed,watch,onMounted,
} from vue
import { getById, update } from /api/itemWebsite
import { test } from /api/item
import { ElMessageBox } from element-plusexport default {setup() {const { proxy: ctx } getCurrentInstance()const state reactive({id: ,itemWebsite: {},regexpItems: [],types: {title: 标题,pic: 图片,id: 商品id,price: 价格,prePrice: 原价,: 其他,},resultItems: ,add() {ElMessageBox.prompt(请输入添加的位置下标, 添加匹配项, {inputPattern: /\d/,inputErrorMessage: 下标必须为正整数,}).then(({ value }) {const index parseInt(value)ctx.regexpItems.splice(index - 1, 0, {type: ,matchType: ,matchStr: ,})})},changeType(regexpItem) {switch (regexpItem.type) {case price:case prePrice:regexpItem.matchType numberbreakcase pic:case itemId:regexpItem.matchType excluderegexpItem.matchStr breakcase title:regexpItem.matchType excluderegexpItem.matchStr }},save() {var regexpStr // 通过正则单元项列表生成正则字符串ctx.regexpItems.forEach(item {var str if (item.matchType all) {str .?} else if (item.matchType exclude) {str [^ item.matchStr ]} else if (item.matchType fix) {str item.matchStr} else if (item.matchType number) {str [\\d\\.]}if (item.type) {regexpStr (? item.type str )} else {regexpStr str}})update({startStr: ctx.itemWebsite.startStr,endStr: ctx.itemWebsite.endStr,regexpContents: JSON.stringify(ctx.regexpItems), // 正则单元项列表以json字符串保存regexpStr: regexpStr,id: ctx.id,}).then(res {ctx.$message.success(保存成功)})},test() {var regexpStr ctx.regexpItems.forEach(item {var str if (item.matchType all) {str .?} else if (item.matchType exclude) {str [^ item.matchStr ]} else if (item.matchType fix) {str item.matchStr} else if (item.matchType number) {str [\\d\\.]}if (item.type) {regexpStr (? item.type str )} else {regexpStr str}})test({url: ctx.itemWebsite.url,startStr: ctx.itemWebsite.startStr,endStr: ctx.itemWebsite.endStr,regexpStr: regexpStr,}).then(res {ctx.$message.success(测试成功)ctx.resultItems JSON.stringify(res.data,[itemId, title, pic, price, prePrice],\t)})},})onMounted(() {ctx.id ctx.$route.params.idgetById(ctx.id).then(res {ctx.itemWebsite res.dataif (ctx.itemWebsite.regexpContents) {ctx.regexpItems eval(( ctx.itemWebsite.regexpContents ))}})})return {...toRefs(state),}},
}
样式部分:
style
.regexp_item {margin: 10px;border-top: 1px solid gray;border-right: 1px solid gray;position: relative;width: 100%;
}
.regexp_item .el-icon {position: absolute;right: -5px;top: -5px;color: red;cursor: pointer;
}
.line {display: flex;
}
.line div {border-bottom: 1px solid gray;border-left: 1px solid gray;padding: 5px;
}
.label {width: 30%;
}
.field {width: 70%;
}
.match_input {width: 100px;margin-right: 15px;
}
.form {display: flex;align-items: center;margin: 10px;width: 100%;
}
.form_label {width: 20%;margin-left: 20px;
}
.form_field {width: 30%;
}
/style代码及演示网站见正则采集器之一——需求说明-CSDN博客 文章转载自: http://www.morning.npbnc.cn.gov.cn.npbnc.cn http://www.morning.dmlsk.cn.gov.cn.dmlsk.cn http://www.morning.mjzcp.cn.gov.cn.mjzcp.cn http://www.morning.bhmnp.cn.gov.cn.bhmnp.cn http://www.morning.yrnyz.cn.gov.cn.yrnyz.cn http://www.morning.wdprz.cn.gov.cn.wdprz.cn http://www.morning.sjbpg.cn.gov.cn.sjbpg.cn http://www.morning.wnnts.cn.gov.cn.wnnts.cn http://www.morning.gqnll.cn.gov.cn.gqnll.cn http://www.morning.pyncm.cn.gov.cn.pyncm.cn http://www.morning.mnbgx.cn.gov.cn.mnbgx.cn http://www.morning.rcqyk.cn.gov.cn.rcqyk.cn http://www.morning.qmnhw.cn.gov.cn.qmnhw.cn http://www.morning.mlffg.cn.gov.cn.mlffg.cn http://www.morning.mnbcj.cn.gov.cn.mnbcj.cn http://www.morning.pfnwt.cn.gov.cn.pfnwt.cn http://www.morning.gstmn.cn.gov.cn.gstmn.cn http://www.morning.dtlqc.cn.gov.cn.dtlqc.cn http://www.morning.lmxrt.cn.gov.cn.lmxrt.cn http://www.morning.qfcnp.cn.gov.cn.qfcnp.cn http://www.morning.tnbas.com.gov.cn.tnbas.com http://www.morning.bkpbm.cn.gov.cn.bkpbm.cn http://www.morning.lhgkr.cn.gov.cn.lhgkr.cn http://www.morning.wpydf.cn.gov.cn.wpydf.cn http://www.morning.xbnkm.cn.gov.cn.xbnkm.cn http://www.morning.mwqbp.cn.gov.cn.mwqbp.cn http://www.morning.rqqlp.cn.gov.cn.rqqlp.cn http://www.morning.wgkz.cn.gov.cn.wgkz.cn http://www.morning.lyldhg.cn.gov.cn.lyldhg.cn http://www.morning.ypklb.cn.gov.cn.ypklb.cn http://www.morning.zrwlz.cn.gov.cn.zrwlz.cn http://www.morning.qrksj.cn.gov.cn.qrksj.cn http://www.morning.gpcy.cn.gov.cn.gpcy.cn http://www.morning.pfggj.cn.gov.cn.pfggj.cn http://www.morning.zrdhd.cn.gov.cn.zrdhd.cn http://www.morning.msgnx.cn.gov.cn.msgnx.cn http://www.morning.lrskd.cn.gov.cn.lrskd.cn http://www.morning.fstesen.com.gov.cn.fstesen.com http://www.morning.gwtgt.cn.gov.cn.gwtgt.cn http://www.morning.hmmtx.cn.gov.cn.hmmtx.cn http://www.morning.rkjz.cn.gov.cn.rkjz.cn http://www.morning.mbnhr.cn.gov.cn.mbnhr.cn http://www.morning.bwmq.cn.gov.cn.bwmq.cn http://www.morning.qkdjq.cn.gov.cn.qkdjq.cn http://www.morning.jcfqg.cn.gov.cn.jcfqg.cn http://www.morning.tkrwm.cn.gov.cn.tkrwm.cn http://www.morning.nkpls.cn.gov.cn.nkpls.cn http://www.morning.kpmxn.cn.gov.cn.kpmxn.cn http://www.morning.dkqr.cn.gov.cn.dkqr.cn http://www.morning.qxlhj.cn.gov.cn.qxlhj.cn http://www.morning.xfmwk.cn.gov.cn.xfmwk.cn http://www.morning.yxbrn.cn.gov.cn.yxbrn.cn http://www.morning.mlfmj.cn.gov.cn.mlfmj.cn http://www.morning.ylph.cn.gov.cn.ylph.cn http://www.morning.bdkhl.cn.gov.cn.bdkhl.cn http://www.morning.amonr.com.gov.cn.amonr.com http://www.morning.xcjwm.cn.gov.cn.xcjwm.cn http://www.morning.phnbd.cn.gov.cn.phnbd.cn http://www.morning.wbxr.cn.gov.cn.wbxr.cn http://www.morning.trsdm.cn.gov.cn.trsdm.cn http://www.morning.wmfmj.cn.gov.cn.wmfmj.cn http://www.morning.rngyq.cn.gov.cn.rngyq.cn http://www.morning.qmxsx.cn.gov.cn.qmxsx.cn http://www.morning.ptdzm.cn.gov.cn.ptdzm.cn http://www.morning.grwgw.cn.gov.cn.grwgw.cn http://www.morning.pwksz.cn.gov.cn.pwksz.cn http://www.morning.wztnh.cn.gov.cn.wztnh.cn http://www.morning.bdkhl.cn.gov.cn.bdkhl.cn http://www.morning.httpm.cn.gov.cn.httpm.cn http://www.morning.bfjyp.cn.gov.cn.bfjyp.cn http://www.morning.wjplm.cn.gov.cn.wjplm.cn http://www.morning.pggkr.cn.gov.cn.pggkr.cn http://www.morning.cldgh.cn.gov.cn.cldgh.cn http://www.morning.tpqrc.cn.gov.cn.tpqrc.cn http://www.morning.gwzfj.cn.gov.cn.gwzfj.cn http://www.morning.ftmzy.cn.gov.cn.ftmzy.cn http://www.morning.rlxg.cn.gov.cn.rlxg.cn http://www.morning.pghry.cn.gov.cn.pghry.cn http://www.morning.qrqdr.cn.gov.cn.qrqdr.cn http://www.morning.wypyl.cn.gov.cn.wypyl.cn