整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          優(yōu)客365程序 文章采集教程

          . 新建采集規(guī)則



          1.1添加采集節(jié)點信息




          規(guī)則寫好后,采集測試下,看內容是否正常,內容正確就可以。



          1.1.1名稱:按照平臺名稱+采集分類 格式

          如:中國青年網(wǎng)-財經(jīng)

          1.1.2列表地址:就是需要采集的新聞所在列表的href地址

          說明:找到要采集的新聞平臺的,某個分類的列表,必須是可以點擊分頁的,流加載的無法采集,這里就拿 中國青年網(wǎng)舉例 點擊體育分類 打開體育列表。注意必須是一相同性質的 列表模式,才方便采集,復制列表地址到插件列表地址。



          先點擊分頁,獲得分頁地址:如 http://news.youth.cn/zc/index_1.htm 可知道 index_1 是分頁參數(shù) 把 index_1 改成index_{page}

          插件中的列表地址就是:http://news.youth.cn/zc/index_{page}.htm

          鍵盤按f12 然后點擊圖中小圖標,把鼠標指向 頁面中需要采集的 文章列表標題中

          比如這里的列表規(guī)則可以寫成: 格式 JQuery選擇名稱,采集的屬性

          列表規(guī)則所以是 .tj3_1>li>a, href ( 從外層到內層尋找定位的。)

          1.1.3文章詳情采集:

          在列表中隨便打開一個文章信息

          這里主要獲取文章標題和文章內容就可以了



          按 F12 打開審查元素,然后點擊左側小圖標




          鼠標定位到 文章標題 ,找到文章標題定位的位置,如果文章標題 的標簽是h1,為了匹配正確放置頁面還有其他地方有h1,所欲必須向上在找一個class 或者id 名稱來定位。



          文章標題規(guī)則:所以這里選擇:.page_title> h1,text作為文章標題規(guī)則 text 位固定格式



          文章內容匹配:

          鼠標定位到文章內容部分:可以看到文章內容上方的 class 或者id ,必須把所有文章內容都包含的元素內部。這里選擇 class=”TRS_Editor” 選擇器就是 .TRS_Editor

          按照采集的格式 :選擇器+html

          采集文章內容 .TRS_Editor,html

          入庫設置:

          規(guī)則寫好后先保存下,然后測試,直到測試正確為止。

          html中,我們經(jīng)常會用到table布局;有時候需要實現(xiàn)指定單元格,當鼠標移動到上面的時候,該單元格背景變色,不是該行背景變色,也不是僅僅文字的背景變色;


          html的文件結構大家都是知道的了,總體分為head和body部分

          我們要實現(xiàn)變色,在head部分實現(xiàn)格式

          <style>

          .tablex {border-collapse: collapse;}

          .tablex tr {}

          .tablex tr td {text-align:center; line-height:30px;}

          .tablex tr td:hover { background-color:#f00; color:#fff;}

          </style>

          然后在body部分,使用table時候,注明class="tablex".這樣的話,就實現(xiàn)了我們所說的效果了。

          附上完整代碼:

          <html>

          <head>

          <meta http-equiv="Content-Type" content="text/html; charset=GBK" />

          <title>測試鼠標移到到表格單元格背景顏色改變的</title>

          <style>

          .table1 {border-collapse: collapse;}

          .table1 tr {}

          .table1 tr td {text-align:center; line-height:30px;}

          .table1 tr td:hover { background-color:#006030; color:#006030;}

          </style>

          </head>

          <body>

          <table class="table1" width="70%" border="1">

          <tr>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          </tr>

          <tr>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          </tr>

          <tr>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          </tr>

          <tr>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          </tr>

          <tr>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          <td>測試</td>

          </tr>

          </table>

          </body>

          </html>

          在任何一個瀏覽器中運行,效果如下




          南大盛聯(lián)20年來一直致力于高端IT培訓--打造高級軟件人才實戰(zhàn)培訓專家,學生對我們的認可是我們一直前進的動力;項目團隊全球招聘,特聘來自海外的老師進行任教,采用100%商業(yè)項目進行實戰(zhàn)培訓,線上線下同步進行。

          課程全部緊隨市場需求進行設計,并且動態(tài)進行調整;7天免費試聽,0首付開始學習,學完后進行100%推薦就業(yè),不滿意工作崗位2次推薦。

          選定一個平臺,認識一群志同道合的朋友,你的未來人生路必定不一樣。

          目前已經(jīng)開設下面這些培訓項目

          Java培訓

          安卓培訓

          JavaWeb培訓

          Linux培訓

          云服務器布置培訓

          HTML5培訓

          SEO培訓

          視頻剪輯培訓

          UI培訓

          歡迎您們分享給自己愿意分享的朋友,大家一起來進步;相互轉告,咨詢,學習。

          南大盛聯(lián)培訓理念:我懂,我也能讓你懂。

          文來源于:程序員成長指北;作者:海闊_天空

          原文:https://juejin.cn/post/7173596154297810957

          如有侵權,聯(lián)系刪除


          前言


          如何快速定位線上bug,是多數(shù)開發(fā)者都會遇到的難題


          web-see[1] 前端監(jiān)控方案,提供了 前端錄屏+定位源碼 方式,讓bug無處藏身


          這是前端監(jiān)控的第二篇,該篇講解如何實現(xiàn)錯誤還原功能,第一篇 從0到1搭建前端監(jiān)控平臺,面試必備的亮點項目總結(已開源)沒有看過的小伙伴,建議先了解下


          最終效果


          在監(jiān)控后臺,通過報錯信息列表,可以查看具體報錯的源碼,以及報錯時的錄屏回放


          效果演示:


          錄屏記錄了用戶的所有操作,紅色的線代表了鼠標的移動軌跡


          定位源碼


          前端項目發(fā)布上線,代碼一般都會進行壓縮、混淆、甚至加密,當線上代碼報錯時,很難定位到具體的源碼


          SourceMap 完美解決了代碼反解的問題,項目在打包時,除了生成最終 XXX.js 文件外,還會額外生成一個 XXX.js.map 的文件


          .map 文件里包含了原始代碼及其映射信息,可以利用它反解出報錯信息的源碼


          SourceMap 文件


          先了解下 SourceMap 的基本內容


          例如 app.a2a3ceec.js 代碼如下:


          var add=function(x, y){return x+y;};
          //# sourceMappingURL=app.a2a3ceec.js.map
          復制代碼


          其中 sourceMappingURL 用來說明該文件對應的map文件


          對應的 app.a2a3ceec.js.map 代碼如下:


          {
            version : 3, // SourceMap標準版本,最新的為3
            file: "js/app.a2a3ceec.js", // 轉換后的文件名
            sourceRoot : "", // 轉換前的文件所在目錄,如果與轉換前的文件在同一目錄,該項為空
            sources: [ // 轉換前的文件,該項是一個數(shù)組,表示可能存在多個文件合并
              "webpack://web-see-demo/./src/App.vue",
              "webpack://web-see-demo/./src/main.js"
            ], 
            names: [], // 轉換前的所有變量名和屬性名
            sourcesContent: [ // 原始文件內容
              "const add = (x,y) => {\n  return x+y;\n}"
            ],
            // 所有映射點
            mappings: "AAAA,IAAM,GAAG,GAAG,UAAC,CAAQ,EAAC,CAAQ;IAC5B,OAAO,CAAC,GAAC,CAAC,CAAC;AACb,CAAC,CAAA"
          }
          復制代碼


          其中 sources 和 sourcesContent 是關鍵字段,下文的還原示例中將用到


          source-map-js 庫


          代碼還原,這里主要使用 source-map-js[3] 庫,下面介紹下如何使用


          示例代碼:


          import sourceMap from 'source-map-js';
          
          /**
          * findCodeBySourceMap用于獲取map文件對應的源代碼
          * @param { string } fileName .map文件名稱
          * @param { number } line 發(fā)生錯誤的行號
          * @param { number } column 發(fā)生錯誤的列號
          * @param { function } 回調函數(shù),返回對應的源碼
          */
          const findCodeBySourceMap = async ({ fileName, line, column }, callback) => {
            // loadSourceMap 用于獲取服務器上 .map 的文件內容
            let sourceData = await loadSourceMap(fileName);
            let { sourcesContent, sources } = sourceData;
            // SourceMapConsumer實例表示一個已解析的源映射
            // 可以通過在生成的源中給它一個文件位置來查詢有關原始文件位置的信息
            let consumer = await new sourceMap.SourceMapConsumer(sourceData);
            // 輸入錯誤的發(fā)生行和列,可以得到源碼對應原始文件、行和列信息
            let result = consumer.originalPositionFor({
              line: Number(line),
              column: Number(column)
            });
            // 從sourcesContent得到具體的源碼信息
            let code = sourcesContent[sources.indexOf(result.source)];
            ……
            callback(code)
          復制代碼


          本小節(jié)的代碼倉庫[4]


          source-map 的還原流程:


          1、從服務器獲取指定.map 的文件內容


          2、new 一個 SourceMapConsumer 的實例,表示一個已解析的源映射,給它一個文件位置來查詢有關原始文件位置的信息


          3、輸入報錯發(fā)生的行和列,可以得到源碼對應原始文件名、行和列信息


          4、從源文件的 sourcesContent 字段中,獲取對應的源碼信息


          接下來的重點就變?yōu)椋喝绾潍@取報錯發(fā)生的原始文件名、行和列信息


          error-stack-parser 庫


          通過第一篇文章的介紹,我們知道可以通過多種方式來捕獲報錯


          比如 error事件、unhandledrejection事件、vue 中通過Vue.config.errorHander、react中通過componentDidCatch


          為了消除各瀏覽器的差異,使用 error-stack-parser[5] 庫來提取給定錯誤的原始文件名、行和列信息


          示例代碼:


          import ErrorStackParser from 'error-stack-parser';
          
          ErrorStackParser.parse(new Error('BOOM'));
          
          // 返回值 StackFrame 堆棧列表
          [
              StackFrame({functionName: 'foo', args: [], fileName: 'path/to/file.js', lineNumber: 35, columnNumber: 79, isNative: false, isEval: false}),
              StackFrame({functionName: 'Bar', fileName: 'https://cdn.somewherefast.com/utils.min.js', lineNumber: 1, columnNumber: 832, isNative: false, isEval: false, isConstructor: true}),
              StackFrame(... and so on ...)
          ]
          復制代碼


          這里簡單說明下 JS 堆棧列表


          堆棧示例:


          function c() {
            try {
              var bar = baz;
              throw new Error()
            } catch (e) {
              console.log(e.stack);
            }
          }
          function b() {
            c();
          }
          function a() {
            b();
          }
          a();
          復制代碼


          上述代碼中會在執(zhí)行到 c 函數(shù)的時候報錯,調用棧為 a -> b -> c,如下圖所示:



          一般我們只需要定位到 c 函數(shù)的堆棧信息,所以使用 error-stack-parser 庫的時候,只取 StackFrame 數(shù)組中的第一個元素


          最終代碼:


          import ErrorStackParser from 'error-stack-parser';
          
          // 取StackFrame數(shù)組中的第一個元素
          let stackFrame = ErrorStackParser.parse(error)[0];
          // 獲取對應的原始文件名、行和列信息,并上報
          let { fileName, columnNumber, lineNumber } = stackFrame;
          復制代碼


          示例演示


          下載 web-see-demo[6] 安裝并運行


          1)點擊 js錯誤 按鈕,會執(zhí)行 HomeView.vue 文件中的 codeErr 方法


          codeErr的源碼為:



          codeErr.png


          2)Vue.config.errorHander中捕獲到報錯信息為:



          length.png


          3)使用 ErrorStackParser.parse 解析后的stackFrame為:



          stackFrame.png


          4)經(jīng)過 consumer.originalPositionFor 還原后的 result 結果為:



          result.png


          5)最終拿到的源碼:



          code.png


          流程總結



          sourcemap.png


          如上圖所示,定位源碼流程總結:


          1、項目中引入監(jiān)控 SDK,打包后將js文件發(fā)布到服務器上


          2、將 .map 文件放到指定的地址,統(tǒng)一存儲


          3、當線上代碼報錯時,利用 error-stack-parser 獲取具體原始文件名、行和列信息,并上報


          4、利用 source-map 從 .map 文件中得到對應的源碼并展示


          前端錄屏


          web-see 監(jiān)控通過 rrweb[7] 提供了前端錄屏的功能


          rrweb 使用


          先介紹下在vue中如何使用


          錄制示例:


          import { record } from 'rrweb';
          // events存儲錄屏信息
          let events = [];
          // record 用于記錄 `DOM` 中的所有變更
          rrweb.record({
            emit(event, isCheckout) {
              // isCheckout 是一個標識,告訴你重新制作了快照
              if (isCheckout) {
                events.push([]);
              }
              events.push(event);
            },
            recordCanvas: true, // 記錄 canvas 內容
            checkoutEveryNms: 10 * 1000, // 每10s重新制作快照
            checkoutEveryNth: 200, // 每 200 個 event 重新制作快照
          });
          復制代碼


          播放示例:


          <template>
            <div ref='player'>
            </div>
          </template>
          <script>
          import rrwebPlayer from 'rrweb-player';
          import 'rrweb-player/dist/style.css';
          export default {
             mounted() {
               // 將記錄的變更按照對應的時間一一重放
               new rrwebPlayer(
                  {
                    target: this.$refs.player, // 回放所需要的HTML元素
                    data: { events }
                  },
                  {
                    UNSAFE_replayCanvas: true // 回放 canvas 內容
                  }
               )
             }
          }
          </script>
          復制代碼


          rrweb 原理淺析


          rrweb 主要由 rrweb 、 rrweb-player 和 rrweb-snapshot 三個庫組成:


          1)rrweb:提供了 record 和 replay 兩個方法;record 方法用來記錄頁面上 DOM 的變化,replay 方法支持根據(jù)時間戳去還原 DOM 的變化


          2)rrweb-player:基于 svelte 模板實現(xiàn),為 rrweb 提供了回放的 GUI 工具,支持暫停、倍速播放、拖拽時間軸等功能。內部調用了 rrweb 的提供的 replay 等方法


          3)rrweb-snapshot:包括 snapshot 和 rebuilding 兩大特性,snapshot 用來序列化 DOM 為增量快照,rebuilding 負責將增量快照還原為 DOM


          rrweb 整體流程:


          1)rrweb 在錄制時會首先進行首屏 DOM 快照,遍歷整個頁面的 DOM 樹,轉換為 JSON 結構數(shù)據(jù),使用增量快照的處理方式,通過 mutationObserver 獲取 DOM 增量變化,同步轉換為 JSON 數(shù)據(jù)進行存儲


          2)整個錄制的過程會生成 unique id,來確定增量數(shù)據(jù)所對應的 DOM 節(jié)點,通過 timestamp 保證回放順序。


          3) 回放時,會創(chuàng)建一個 iframe 作為承載事件回放的容器,針對首屏 DOM 快照進行重建,在遍歷 JSON 的同時,根據(jù)序列化后的節(jié)點數(shù)據(jù)構建出實際的 DOM 節(jié)點


          4)rrweb 可以監(jiān)聽的用戶行為包括:鼠標移動,鼠標交互,頁面滾動,視窗變化、用戶輸入等,通過添加相應的監(jiān)聽事件來實現(xiàn)


          壓縮數(shù)據(jù)


          如果一直錄屏,數(shù)據(jù)量是巨大的


          實測下來,錄制10s的時長,數(shù)據(jù)大小約為 8M 左右(頁面的不同復雜度、用戶不同操作的頻率都會造成大小不一樣)


          數(shù)據(jù)如果不經(jīng)過壓縮,直接傳給后端,面對大量的用戶,需要非常高的帶寬做支持。還好,rrweb官方提供了數(shù)據(jù)壓縮函數(shù)[8]


          基于 packFn 的單數(shù)據(jù)壓縮,在錄制時可以作為 packFn 傳入


          rrweb.record({
            emit(event) {},
            packFn: rrweb.pack,
          });
          復制代碼


          回放時,需要傳入 rrweb.unpack 作為 unpackFn 傳入


          const replayer = new rrweb.Replayer(events, {
            unpackFn: rrweb.unpack,
          });
          復制代碼


          但是官方提供的壓縮方式,是對每個 event 數(shù)據(jù)單獨進行壓縮,壓縮比不高。實測下來,壓縮比在70%左右,比如原來 8M 的數(shù)據(jù),壓縮后為 2.4M 左右


          官方更加推薦將多個 event 批量一次性壓縮,這樣壓縮效果更好


          web-see 內部使用 pako.js[9]、js-base64[10] 相結合的壓縮方式,實測下來,壓縮比為 85% 以上,原來 8M 的數(shù)據(jù),壓縮后為 1.2M 左右


          壓縮代碼示例:


          import pako from 'pako';
          import { Base64 } from 'js-base64';
          
          // 壓縮
          export function zip(data) {
            if (!data) return data;
            // 判斷數(shù)據(jù)是否需要轉為JSON
            const dataJson = typeof data !== 'string' && typeof data !== 'number' ? JSON.stringify(data) : data;
            // 使用Base64.encode處理字符編碼,兼容中文
            const str = Base64.encode(dataJson);
            let binaryString = pako.gzip(str);
            let arr = Array.from(binaryString);
            let s = '';
            arr.forEach((item) => {
              s += String.fromCharCode(item);
            });
            return Base64.btoa(s);
          }
          復制代碼


          解壓代碼示例:


          import { Base64 } from 'js-base64';
          import pako from 'pako';
          
          // 解壓
          export function unzip(b64Data) {
            let strData = Base64.atob(b64Data);
            let charData = strData.split('').map(function (x) {
              return x.charCodeAt(0);
            });
            let binData = new Uint8Array(charData);
            let data = pako.ungzip(binData);
            // ↓切片處理數(shù)據(jù),防止內存溢出報錯↓
            let str = '';
            const chunk = 8 * 1024;
            let i;
            for (i = 0; i < data.length / chunk; i++) {
              str += String.fromCharCode.apply(null, data.slice(i * chunk, (i + 1) * chunk));
            }
            str += String.fromCharCode.apply(null, data.slice(i * chunk));
            // ↑切片處理數(shù)據(jù),防止內存溢出報錯↑
            const unzipStr = Base64.decode(str);
            let result = '';
            // 對象或數(shù)組進行JSON轉換
            try {
              result = JSON.parse(unzipStr);
            } catch (error) {
              if (/Unexpected token o in JSON at position 0/.test(error)) {
                // 如果沒有轉換成功,代表值為基本數(shù)據(jù),直接賦值
                result = unzipStr;
              }
            }
            return result;
          }
          復制代碼


          何時上報錄屏數(shù)據(jù)


          一般關注的是,頁面報錯的時候用戶做了哪些操作,所以目前只把報錯前10s的錄屏上報到服務端


          如何只上報報錯時的錄屏信息呢 ?


          1)window上設置 hasError、recordScreenId 變量,hasError用來判斷某段時間代碼是否報錯;recordScreenId 用來記錄此次錄屏的id


          2)當頁面發(fā)出報錯需要上報時,判斷是否開啟了錄屏,如果開啟了,將 hasError 設為 true,同時將 window 上的 recordScreenId,存儲到此次上報信息的 data 中


          3)rrweb 設置10s重新制作快照的頻率,每次重置錄屏時,判斷 hasError 是否為 true(即這段時間內是否發(fā)生報錯),有的話將這次的錄屏信息上報,并重置錄屏信息和 recordScreenId,作為下次錄屏使用


          4)后臺報錯列表,從本次報錯報的data中取出 recordScreenId 來播放錄屏


          錄屏的代碼示例:


          handleScreen() {
           try {
            // 存儲錄屏信息
            let events = [];
            record({
              emit(event, isCheckout) {
                if (isCheckout) {
                  // 此段時間內發(fā)生錯誤,上報錄屏信息
                  if (_support.hasError) {
                    let recordScreenId = _support.recordScreenId;
                    // 重置recordScreenId,作為下次使用
                    _support.recordScreenId = generateUUID();
                    transportData.send({
                      type: EVENTTYPES.RECORDSCREEN,
                      recordScreenId,
                      time: getTimestamp(),
                      status: STATUS_CODE.OK,
                      events: zip(events)
                    });
                    events = [];
                    _support.hasError = false;
                  } else {
                    // 不上報,清空錄屏
                    events = [];
                    _support.recordScreenId = generateUUID();
                  }
                }
                events.push(event);
              },
              recordCanvas: true,
              // 默認每10s重新制作快照
              checkoutEveryNms: 1000 * options.recordScreentime
            });
          復制代碼


          遺留問題,在線求解


          按照官方的 canvas 配置,驗證下來,rrweb 還是不支持 canvas 的錄制,比如使用 echarts 畫圖,圖形區(qū)域的錄屏顯示是空白的


          官方配置[11] 如下:



          Canvas.png


          測試demo[12] 如下:



          echart.png


          錄屏回放,圖形這塊區(qū)域是空白的:



          canvas.gif


          主站蜘蛛池模板: 在线观看国产一区二区三区| 亚洲熟女一区二区三区| 亚洲天堂一区在线| 无码一区二区三区免费| 久久一区二区明星换脸| 无码人妻精品一区二区三区夜夜嗨| 亚洲高清成人一区二区三区| 亚洲国产一区视频| 精品乱人伦一区二区三区| 精品国产免费一区二区三区香蕉| 亚洲综合国产一区二区三区| 亚洲韩国精品无码一区二区三区| 插我一区二区在线观看| 国产精品一区二区久久| 精彩视频一区二区三区| 波多野结衣AV无码久久一区| 无码播放一区二区三区| 天码av无码一区二区三区四区| 亚洲av午夜福利精品一区| 蜜臀AV免费一区二区三区| 免费一区二区三区四区五区| 久久精品一区二区免费看| 精品不卡一区中文字幕| 乱精品一区字幕二区| 白丝爆浆18禁一区二区三区| 69福利视频一区二区| 国产午夜精品一区二区三区漫画| 亚洲AV无码一区二区一二区| 国产精品一区三区| 精品一区二区三区电影| 久热国产精品视频一区二区三区| 日韩精品一区二区三区大桥未久| 国产在线观看一区二区三区| 91精品福利一区二区| 人妻无码视频一区二区三区| 久久一区二区三区免费播放| 国产无码一区二区在线| 熟女少妇丰满一区二区| 亚洲午夜日韩高清一区| 久久久久女教师免费一区| 色老板在线视频一区二区|